010 函數(shù)指針

函數(shù)指針指向的是函數(shù)而非對(duì)象绎秒。和其他指針一樣一姿,函數(shù)指針指向某種特定類型拖云。函數(shù)的類型由它的返回類型和形參類型共同決定那伐,與函數(shù)名稱無(wú)關(guān)踏施。例如:

bool LengthCompare(const std::string&, const std::string&);

該函數(shù)的類型是 bool (const std::string&, const std::string&)。要想聲明一個(gè)可以指向該函數(shù)的指針罕邀,只需要用指針替換函數(shù)名即可:

bool (*lcPtr)(const std::string&, const std::string&);

注意:*lcPtr 兩端的括號(hào)必不可少畅形。如果不寫這對(duì)括號(hào),則 lcPtr 是一個(gè)返回值為 bool 指針的函數(shù)诉探。

使用函數(shù)指針

當(dāng)我們把函數(shù)名作為一個(gè)值使用時(shí)日熬,該函數(shù)自動(dòng)轉(zhuǎn)換為指針。例如:

lcPtr = LengthCompare;    // lcPtr 指向名為 LengthCompare 的函數(shù)
lcPtr = &LengthCompare;   // 等價(jià)的賦值語(yǔ)句:取地址符是可選的

此外肾胯,我們還能直接使用指向函數(shù)的指針調(diào)用該函數(shù)竖席,無(wú)須提前解引用指針:

bool b1 = lcPtr("Hello", "World!");     // 調(diào)用 LengthCompare 函數(shù)
bool b2 = (*lcPtr)("Hello", "World!");  // 一個(gè)等價(jià)的調(diào)用
bool b3 = LengthCompare("Hello", "World!"); // 另一個(gè)等價(jià)的調(diào)用

在指向不同函數(shù)類型的指針間不存在轉(zhuǎn)換規(guī)則。但是和往常一樣敬肚,我們可以為函數(shù)指針賦值一個(gè) nullptr毕荐,表示該指針沒(méi)有指向任何一個(gè)函數(shù):

bool LengthCompare(const std::string&, const std::string&);
bool (*lcPtr)(const std::string&, const std::string&);
std::string::size_type sumLength(const std::string&, const std::string&);
bool cstringCompare(const char*, const char*);

lcPtr = nullptr;    // 正確:形參類型不匹配
lcPtr = sumLength;  // 錯(cuò)誤:返回類型不匹配
lcPtr = cstringCompare; // 錯(cuò)誤:形參類型不匹配
lcPtr = LengthCompare;  // 正確:函數(shù)和指針的類型精確匹配

重載函數(shù)的指針

當(dāng)我們使用重載函數(shù)時(shí),代碼必須清晰地指明到底應(yīng)該使用哪個(gè)函數(shù)艳馒。例如:

void ff(int*);
void ff(unsigned);

編譯器通過(guò)指針類型決定選用哪個(gè)函數(shù)憎亚,指針類型必須與重載函數(shù)中的某一個(gè)精確匹配:

void ff(int*);
void ff(unsigned);
void (*pf1)(unsigned) = ff;  // pf1 指向 ff(unsigned)
void (*pf2)(int) = ff;  // 錯(cuò)誤
void (*pf3)(int*) = ff;  // 錯(cuò)誤

函數(shù)指針形參

和數(shù)組類似,雖然不能定義函數(shù)類型的形參弄慰,但是形參可以是指向函數(shù)的指針第美。此時(shí),形參看起來(lái)是函數(shù)類型陆爽,實(shí)際上卻是當(dāng)成指針使用:

// 第三個(gè)參數(shù)是函數(shù)類型什往,它會(huì)自動(dòng)地轉(zhuǎn)換成指向函數(shù)的指針
void useBigger(const std::string &s1, const std::string &s2, bool pf(const std::string&, const std::string&));
// 等價(jià)的聲明:顯示地將形參定義成指向函數(shù)的指針
void useBigger(const std::string &s1, const std::string &s2, bool (*pf)(const std::string&, const std::string&));

我們可以直接把函數(shù)作為實(shí)參使用,此時(shí)它會(huì)自動(dòng)轉(zhuǎn)換成指針:

useBigger(s1, s2, LengthCompare);

useBigger 的聲明語(yǔ)句看起來(lái)冗長(zhǎng)而繁瑣慌闭。類型別名和 decltype 能讓我們簡(jiǎn)化使用了函數(shù)指針的代碼:

// Func1 和 Func2 是函數(shù)類型
typedef bool Func1(const std::string&, const std::string&);
typedef decltype (LengthCompare) Func2; // 等價(jià)的類型
// FuncP1 和 FuncP2 是指向函數(shù)的指針
typedef bool (*FuncP1)(const std::string&, const std::string&);
typedef decltype (LengthCompare) *FuncP2; // 等價(jià)的類型

然后别威,可以使用如下方式改寫 useBigger:

void useBigger(const std::string &s1, const std::string &s2, Func1);
void useBigger(const std::string &s1, const std::string &s2, FuncP2);

返回指向函數(shù)的指針

與數(shù)組類似第献,雖然不能返回一個(gè)函數(shù),但是能返回指向函數(shù)類型的指針兔港。然而,我們必須把返回類型寫成指針形式衫樊,編譯器不會(huì)自動(dòng)地將函數(shù)返回類型當(dāng)成對(duì)應(yīng)的指針類型處理飒赃。要想聲明一個(gè)返回函數(shù)指針的函數(shù),最簡(jiǎn)單的方法是借助類型別名:

using F = int(int*, int);    // F 是函數(shù)類型载佳,不是指針
using PF = int(*)(int*, int);  // PF 是指針類型

我們必須顯式地將返回類型指定為指針:

PF f1(int);    // 正確:PF 是指向函數(shù)的指針,f1 返回指向函數(shù)的指針
F f2(int);    // 錯(cuò)誤:F 是函數(shù)類型,f2 不能返回一個(gè)函數(shù)
F *f3(int);    // 正確

當(dāng)然黍析,我們也能用下面的形式直接地聲明 f1:

int (*f1(int))(int*, int);

另外,我們還可以使用尾置返回類型的方式:

auto f1(int)->int (*)(int*, int);

將 auto 和 decltype 用于函數(shù)指針類型

如果我們明確知道返回的函數(shù)是哪一個(gè)奄抽,就能使用 decltype 簡(jiǎn)化書(shū)寫函數(shù)指針?lè)祷仡愋偷倪^(guò)程蔼两。例如假定有兩個(gè)函數(shù),它們的返回類型都是 std::string::size_type逞度,并且各有兩個(gè) const std::string& 類型的形參额划,此時(shí)我們可以編寫第三個(gè)函數(shù),它接受一個(gè) std::string 類型的參數(shù)第晰,返回一個(gè)指針锁孟,該指針指向前兩個(gè)函數(shù)中的一個(gè):

std::string::size_type sumLength(const std::string&, const std::string&);
std::string::size_type largerLength(const std::string&, const std::string&);
// 根據(jù)其形參的取值彬祖,getFcn 函數(shù)返回指向 sumLength 或者 largerLength 的指針
decltype (sumLength) *getFcn(const std::string&);

聲明 getFcn 唯一需要注意的地方是茁瘦,牢記當(dāng)我們將 decltype 作用于某個(gè)函數(shù)時(shí),它返回函數(shù)類型而非指針類型储笑。因此甜熔,我們顯示地加上 * 以表明我們需要返回指針,而非函數(shù)本身突倍。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末腔稀,一起剝皮案震驚了整個(gè)濱河市盆昙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌焊虏,老刑警劉巖淡喜,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異诵闭,居然都是意外死亡炼团,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門疏尿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)瘟芝,“玉大人,你說(shuō)我怎么就攤上這事褥琐⌒烤悖” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵敌呈,是天一觀的道長(zhǎng)贸宏。 經(jīng)常有香客問(wèn)我,道長(zhǎng)磕洪,這世上最難降的妖魔是什么锚赤? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮褐鸥,結(jié)果婚禮上线脚,老公的妹妹穿的比我還像新娘。我一直安慰自己叫榕,他們只是感情好浑侥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著晰绎,像睡著了一般寓落。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荞下,一...
    開(kāi)封第一講書(shū)人閱讀 51,231評(píng)論 1 299
  • 那天伶选,我揣著相機(jī)與錄音,去河邊找鬼尖昏。 笑死仰税,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抽诉。 我是一名探鬼主播陨簇,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼迹淌!你這毒婦竟也來(lái)了河绽?” 一聲冷哼從身側(cè)響起己单,我...
    開(kāi)封第一講書(shū)人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎耙饰,沒(méi)想到半個(gè)月后纹笼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡苟跪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年允乐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片削咆。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡牍疏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拨齐,到底是詐尸還是另有隱情鳞陨,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布瞻惋,位于F島的核電站厦滤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏歼狼。R本人自食惡果不足惜掏导,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望羽峰。 院中可真熱鬧趟咆,春花似錦、人聲如沸梅屉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)坯汤。三九已至虐唠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惰聂,已是汗流浹背疆偿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搓幌,地道東北人杆故。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鼻种,于是被迫代替她去往敵國(guó)和親反番。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容