您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“C++中函數(shù)指針有什么用”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“C++中函數(shù)指針有什么用”這篇文章吧。
函數(shù)指針顧名思義,就是指向函數(shù)的指針。
和數(shù)據(jù)類似,C++當(dāng)中函數(shù)也有地址,函數(shù)的地址是存儲(chǔ)函數(shù)機(jī)器語言代碼的內(nèi)存地址。我們可以將另外一個(gè)函數(shù)的地址作為參數(shù)傳入函數(shù),從而實(shí)現(xiàn)函數(shù)的靈活調(diào)用。
獲取函數(shù)地址的方法非常簡單,只要使用函數(shù)名(后面不跟參數(shù)和括號(hào))即可。比如我們有一個(gè)函數(shù)叫做think,那么think()是調(diào)用函數(shù)拿到結(jié)果,而think
則是獲取函數(shù)的地址。
如果我們想要將think函數(shù)當(dāng)做參數(shù)傳入另外一個(gè)函數(shù),我們可以這么寫:
func(think);
聲明函數(shù)指針和聲明函數(shù)類似,我們聲明一個(gè)函數(shù)可以這么寫:
double process(int);
而我們聲明函數(shù)指針則可以寫成這樣:
double (*pt)(int);
如果我們把(*pt)
替換成函數(shù)名的話,這其實(shí)就是一個(gè)函數(shù)的聲明。如果(*pt)
是函數(shù)的話,那么pt自然就是指向函數(shù)的指針了。
如果我們要實(shí)現(xiàn)一個(gè)函數(shù),它的一個(gè)參數(shù)是一個(gè)函數(shù)指針,它的寫法和剛才一樣:
double func(double x, double (*pt)(int));
在這個(gè)聲明當(dāng)中,它的第二個(gè)參數(shù)是一個(gè)函數(shù)指針。指向的函數(shù)接收一個(gè)int參數(shù),返回一個(gè)double
結(jié)果。
最后, 我們來看下通過指針調(diào)用函數(shù)的部分。
其實(shí)也非常簡單,因?yàn)槲覀兦懊嬲f了(*pt)
的效果和函數(shù)是一樣的,我們之前通過函數(shù)名調(diào)用函數(shù),那么我們只需要改成通過(*pt)
調(diào)用即可。
如:
double process(int); double (*pt)(int); pt = process; cout << (*pt)(5) << endl;
簡單的函數(shù)指針比較簡單,但對(duì)于復(fù)雜的情況則顯得有些恐怖。下面我們來看下C++ primer
當(dāng)中提供的一些例子:
const double* f1(const double ar[], int n); const double* f2(const double [], int); const double* f3(const double *, int);
這三個(gè)函數(shù)看起來長得不一樣,但其實(shí)是等價(jià)的。因?yàn)樵诤瘮?shù)參數(shù)列表當(dāng)中,數(shù)組和指針是等價(jià)的。其次我們可以在函數(shù)的原型中省略掉變量名,因此const double ar[]
可以簡化成const double []
,也可以寫成const double *。
有了這三個(gè)函數(shù)之后,假設(shè)我們要聲明一個(gè)指針,指向這三個(gè)函數(shù)。根據(jù)我們前文當(dāng)中說過的,可以將函數(shù)名替換成(*pt)來實(shí)現(xiàn):
const double* (*pt)(const double *, int) = f1;
其實(shí)這個(gè)語句看起來就有些復(fù)雜了,整個(gè)語句的可讀性很差。如果不是知道這里用的是一個(gè)函數(shù)指針,乍一看想要看明白估計(jì)不太容易。我們可以分成兩個(gè)部分來理解,其中const double *
是一個(gè)整體,表示函數(shù)的返回值類型是一個(gè)const double *也就是一個(gè)常量浮點(diǎn)數(shù)的地址。其次(*pt)
是一個(gè)整體,代替了函數(shù)名,表示這是一個(gè)指向函數(shù)的指針。
在C++11當(dāng)中提供了叫做auto
的新特性,它可以幫助變量自動(dòng)識(shí)別對(duì)應(yīng)的類型,可以解決一些類型特別復(fù)雜的問題,比如:
auto p2 = f2;
函數(shù)指針有兩種調(diào)用方法,除了可以使用(*p2)
的方式調(diào)用之外,
也可以直接使用名稱調(diào)用:
const double* x = p2(ar, 3); const double* y = (*p2)(ar, 3);
顯然前者更好,更清楚。這里其實(shí)有一個(gè)疑問,為什么這兩種方式都可以執(zhí)行呢?這是因?yàn)楫?dāng)我們執(zhí)行auto p2 = f2的時(shí)候,其實(shí)是執(zhí)行的auto p2 = &f2
,C++
會(huì)隱式地將函數(shù)轉(zhuǎn)換成函數(shù)的地址。因?yàn)楹瘮?shù)的值本身就是一個(gè)地址,所以這兩種方式才都能正確地運(yùn)行。
問題還沒有結(jié)束,假如我們要定義一個(gè)指向函數(shù)的指針數(shù)組呢?這應(yīng)該怎么聲明?
也就是const double* (*pt)(const double *, int)
這樣一個(gè)類型的數(shù)組,它應(yīng)該怎么聲明,這個(gè)方括號(hào)應(yīng)該放在那里?
正確答案是放在括號(hào)里:
const double* (*pt[3])(const double *, int);
因?yàn)檫\(yùn)算符[]的優(yōu)先級(jí)高于*,因此*pt[3]
表示pt是一個(gè)長度為3的指針數(shù)組。其他的內(nèi)容表明了該指針的類型。
由于我們定義的是一個(gè)數(shù)組,所以這里不能使用auto
,因?yàn)樽詣?dòng)類型推斷只能用于單值初始化而不能用于初始化列表。
到這里還沒結(jié)束,還有更恐怖的,如果我們想要定義一個(gè)指向這個(gè)數(shù)組的指針,應(yīng)該怎么辦呢?如果使用auto可以寫成:
auto ptr = &pt;
如果不使用auto呢?首先我們可以想到,這個(gè)聲明是基于pt的,我們需要在pt的聲明上加上一個(gè)*,但問題是加在哪里呢?
進(jìn)一步分析,會(huì)發(fā)現(xiàn)我們需要指出這是一個(gè)指針,而不是數(shù)組。意味著核心的部分應(yīng)該寫成(*ptr)[3],表示這是一個(gè)指向長度為3的數(shù)組的指針。因?yàn)閇]的優(yōu)先級(jí)更高,所以需要使用括號(hào)。如果寫成*ptr[3]表示這是長度為3的指針數(shù)組。
我們進(jìn)一步倒推,(*ptr)[3]這個(gè)數(shù)組當(dāng)中的元素是什么類型呢?是指向函數(shù)的指針,所以寫出來結(jié)果是這樣:
const double *(*(*ptr)[3])(const double*, int) = &pt;
很明顯,這樣的定義非常非常的難以理解。而且這還不是最復(fù)雜的情況,比如函數(shù)的返回類型又是一個(gè)指向一個(gè)函數(shù)的指針……明擺著告訴我們含義我們?nèi)匀灰魄靡粫?huì),如果在一段不明的代碼當(dāng)中遇到,可能會(huì)直接抓狂吧……
也正因此,C++11當(dāng)中推出了auto
特性,可以簡化這種情況。
多說一句題外話,golang
語言當(dāng)中將變量的類型放在變量的后面而不是前面,其中一個(gè)原因就是為了解決類似情況的復(fù)雜性。
如果是golang來定義同樣的內(nèi)容,會(huì)是這樣的:
func f2(arr []float64, n int) *float64 { // todo } // 函數(shù)指針 var p1 func([]float64, int) *float64 = f2; // 函數(shù)指針數(shù)組 var pt [3]func([]float64, int) *float64; // 函數(shù)指針數(shù)組的指針 var ptr *[3]func([]float64, int) *float64 = &pt;
很明顯,雖然變量類型寫在變量后面剛開始會(huì)不太習(xí)慣,但是很明顯這樣要清晰很多。
以上是“C++中函數(shù)指針有什么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。