C++基礎(chǔ)入門教程(九):函數(shù)指針之回調(diào)
在Java,要實(shí)現(xiàn)某個時間調(diào)用某段代碼,是很簡單的事情,那就是使用接口。
而在C++里,有一個比較高深的方式,那就是使用函數(shù)指針。
比如Cocos2d-x的定時器(schedule)、消息訂閱(NotificationCenter)都使用了函數(shù)指針來完成回調(diào)的功能。
這也是為什么我們總是能把某個函數(shù)作為參數(shù)傳進(jìn)去,然后在某個時刻這個函數(shù)會被調(diào)用。
一、函數(shù)的地址
要獲取一個int變量的地址很簡單,比如int num; 那么num的地址就是&num。
而獲取函數(shù)的地址更簡單,函數(shù)的名字就是函數(shù)的地址,如下代碼:
void hello();
int _tmain(int argc, _TCHAR* argv[])
{
auto p = hello;
p();
return 0;
}
void hello()
{
cout << "helloworld";
}
我們定義了一個hello函數(shù),然后直接把函數(shù)名字賦值給指針p,于是,就可以把p當(dāng)成了hello函數(shù)來使用了。
這很簡單吧。
二、聲明函數(shù)指針
獲取函數(shù)的地址很簡單,但是,如何聲明函數(shù)指針就變得不那么簡單了。
我們總不能每次都使用auto來逃避吧?有時候我們不得不顯式地聲明函數(shù)指針,那么,如何聲明呢?
還記得我們說過的typedef定義類型別名嗎?函數(shù)指針的聲明也是一樣的規(guī)則,先聲明一個函數(shù),如:void hello();
然后把函數(shù)名字換成指針,如:void (*p)();
沒錯,就是這么簡單,void (*p)(); 就是void hello(); 的聲明了。
立刻再來試試,這個函數(shù):int getValue(float dt);
它的函數(shù)指針聲明是什么?沒錯,就是:int (*p) getValue(float dt);
沒錯,就是這么簡單int getValue(float dt); 就是int (*p) getValue(float dt);的函數(shù)指針聲明了。
立刻再來試試,這..(小若:停~!別以為我不在你就可以亂來?。?/p>
好吧,那就不繼續(xù)試了,我們來看看,剛剛那段代碼可以這樣寫:
void hello();
int _tmain(int argc, _TCHAR* argv[])
{
void (*p)();
p = hello;
p();
(*p)(); // 偷偷加了這句
return 0;
}
void hello()
{
cout << "helloworld";
}
好了,很簡單,不多說了~
另外,有沒有發(fā)現(xiàn)我偷偷又加了一句代碼?
沒錯,用(*p)();的方式也通過能成功調(diào)用hello函數(shù),這是為什么呢?
三、歷史原因
由于p是指針,它指向的是hello函數(shù)的地址,所以,*p就代表hello函數(shù),于是,(*p)()就等于hello(),這是正常的邏輯。
所以,其實(shí)(*p)()才是比較正常的調(diào)用方式。
然而,由于函數(shù)名本來就是指向了函數(shù)的指針,也就是說,hello其實(shí)也是指向了函數(shù)的地址。
換句話說,p和hello其實(shí)都是指針,那么,p的調(diào)用方式和hello的調(diào)用方式應(yīng)該也是一樣的,于是,p()就相當(dāng)于hello()。
這兩種方式都是正確的,其實(shí)語法這東西,就是人定的,歷史上前輩對這兩種方式各持所見,于是就容忍了這兩種看似沖突的方式同時存在了。
不過,我想,大部分人都會更喜歡直接用p(),而不是(*p)()吧。
四、typedef挽救復(fù)雜的函數(shù)指針
如下代碼:
string hehe1(int num, float value);
string hehe2(int num, float value);
string hehe3(int num, float value);
int _tmain(int argc, _TCHAR* argv[])
{
/* 聲明函數(shù)指針數(shù)組 */
string(*p[3])(int num, float value) = {hehe1, hehe2, hehe3};
string result = p[1](1, 2);
cout << result.c_str() << endl;
return 0;
}
string hehe1(int num, float value)
{
return "haha1";
}
string hehe2(int num, float value)
{
return "haha2";
}
string hehe3(int num, float value)
{
return "haha3";
}
這段代碼有三個參數(shù)和返回值都相同的函數(shù),分別是hehe1、hehe2、hehe3
然后,我們要聲明一個數(shù)組,這個數(shù)組用來存放這三個函數(shù)指針。
這里的函數(shù)還算是比較簡單的,所以看起來不算復(fù)雜。
但如果這樣的聲明出現(xiàn)太多的話,未免會讓人很沮喪。
于是,typedef挽救了我們,我們可以復(fù)雜的聲明變成這樣:
int _tmain(int argc, _TCHAR* argv[])
{
/* 用HeheFunc來代替復(fù)雜的函數(shù)聲明 */
typedef string(*HeheFunc)(int num, float value);
/* 聲明函數(shù)指針數(shù)組 */
HeheFunc p[3] = { hehe1, hehe2, hehe3 };
string result = p[1](1, 2);
cout << result.c_str() << endl;
return 0;
}
使用typedef代替函數(shù)聲明之后,我們就能很輕松地使用它,并且會讓我們的代表變得很簡單,很好理解。
現(xiàn)在,HeheFunc就代表了一種類型,什么類型呢?就是參數(shù)為(int num, float value),返回值為string的函數(shù)類型。
五、結(jié)束
好了,就嘮叨這么多吧。
- c++內(nèi)聯(lián)函數(shù)(inline)使用詳解
- C++中inline函數(shù)詳解
- c++中的內(nèi)聯(lián)函數(shù)inline用法實(shí)例
- C++ inline內(nèi)聯(lián)函數(shù)詳解
- C++中回調(diào)函數(shù)(CallBack)的用法分析
- C++ 中回調(diào)函數(shù)詳解及簡單實(shí)例
- c++函數(shù)指針和回調(diào)函數(shù)示例
- C++函數(shù)指針和回調(diào)函數(shù)使用解析
- c++回調(diào)之利用函數(shù)指針示例
- C++知識點(diǎn)之inline函數(shù)、回調(diào)函數(shù)和普通函數(shù)
相關(guān)文章
C/C++實(shí)現(xiàn)圖書信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了c/c++實(shí)現(xiàn)圖書信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11使用C++實(shí)現(xiàn)MySQL數(shù)據(jù)庫連接池
這篇文章主要為大家詳細(xì)介紹了如何使用C++實(shí)現(xiàn)MySQL數(shù)據(jù)庫連接池,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,有需要的小伙伴可以了解下2024-03-03C語言調(diào)試手段:鎖定錯誤的實(shí)現(xiàn)方法
本篇文章是對在C語言調(diào)試中,鎖定錯誤的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05利用C++簡單實(shí)現(xiàn)順序表和單鏈表的示例代碼
這篇文章主要給大家介紹了關(guān)于利用C++簡單實(shí)現(xiàn)順序表和單鏈表的方法,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),需要的朋友可以參考借鑒,下面來跟著小編一起來學(xué)習(xí)學(xué)習(xí)吧。2017-08-08C++類與對象深入之運(yùn)算符重載與const及初始化列表詳解
運(yùn)算符是程序中最最常見的操作,例如對于內(nèi)置類型的賦值我們直接使用=賦值即可,因?yàn)檫@些編譯器已經(jīng)幫我們做好了,但是對象的賦值呢?能直接賦值嗎2022-06-06vs2017智能感知錯誤解決代碼標(biāo)紅但編譯通過問題
這篇文章主要介紹了vs2017智能感知錯誤代碼標(biāo)紅但編譯通過問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08