函數的地址是存儲其機器語言代碼的記憶體的開始地址。可以編寫將另一個函數的地址作為參數的函數,它允許在不同的時間傳遞不同函數的地址,這意味著可以在不同的時間使用不同的函數。 ...
函數的地址是存儲其機器語言代碼的記憶體的開始地址。可以編寫將另一個函數的地址作為參數的函數,它允許在不同的時間傳遞不同函數的地址,這意味著可以在不同的時間使用不同的函數。
1 函數指針類型
聲明指向函數的指針時,必須指定函數的返回類型以及函數的特征標(參數列表),可以首先編寫這種函數的原型,然後用 (*pf)
替換函數名,這樣 pf
就是這類函數的指針。以下麵的程式為例,要獲取函數的地址,只需使用函數名即可(後面不跟參數),這與數組地址有幾分相似,函數指針 pf
的類型是 double (*)(int)
,由於 pf
是指向 pam()
函數的指針,因此 (*pf)
是函數,使用函數指針調用函數時,C++ 將 pf
與 (*pf)
看作是等價的(雖然前者是函數指針,後者是函數),將 pf()
用作函數調用與將 (*pf)()
用作函數調用,效果一樣。
//函數原型
double pam(int);
//聲明對應的函數指針
double (*pf)(int);
//賦值,也可在聲明時進行
pf = pam;
//使用函數指針調用函數,以下幾種方式等效
double x = pam(4); //方式一
double x = (*pf)(4); //方式二
double x = pf(4); //方式三
//輸出函數地址
cout << pam; //值為0x001F1384
cout << pf; //值為0x001F1384
對函數指針進行賦值時,對應函數的特征標和返回類型必須與 pf
相同,如果不相同,編譯器將拒絕這種賦值。例如函數指針類型 const double * (*)(const double *, int)
與下麵幾種函數匹配,它們的特征標看似不同,但實際上相同,還可使用 auto
關鍵字自動推斷函數指針的類型。
//函數原型
const double * f1(const double ar[], int n);
const double * f2(const double * ar, int n);
const double * f3(const double [], int);
const double * f4(const double *, int);
//聲明函數指針
const double * (*pf)(const double *, int);
//賦值
pf = f1;
pf = f2;
pf = f3;
pf = f4;
//可使用自動類型推斷
auto pff = f1;
假設要設計一個名為 estimate()
的函數,用於估算編寫指定行數的代碼所需的時間,而且允許每個程式員提供自己的演算法來估算時間,此時可將函數地址作為該函數的輸入參數,其函數原型可使用如下聲明,需保證每個程式員提供的函數特征標和返回類型都一致且與 double (*)(int)
匹配。
//將函數指針作為函數參數
void estimate(int lines, double (*pf)(int));
2 函數指針數組
指向函數指針數組的指針通常用於類的虛方法實現中,細節通常由編譯器自動處理。如下程式所示,函數指針數組大體性質與一維數組相似,其中需要註意的是:
- 運算符
()
與[]
的優先順序比*
要高,因此需在合適的地方使用括弧()
提高*
的優先順序。 - 無法將指針算術運用於函數名,即出現
fb+1
或arrpf[i]+1
時編譯器會報錯。 - 無法將
sizeof()
運用於函數名fb
,但可用於arrpf[i]
,即出現sizeof(fb)
時編譯器會報錯,但sizeof(arrpf[i])
則不會。
//函數原型
double fa(int);
double fb(int);
double fc(int);
double fd(int);
//聲明並初始化函數指針數組
double (*arrpf[4])(int) = {fa,fb,fc,fd};
//聲明並初始化指向函數指針數組第一個元素的指針,以下三種方式對arrpfb等效
double (**arrpfb)(int) = arrpf; //方式一
double (**arrpfb)(int) = &arrpf[0]; //方式二
auto arrpfb = &arrpf[0]; //方式三
//聲明並初始化指向整個函數指針數組的指針,以下兩種方式對arrpfc等效
double (*(*arrpfc)[4])(int) = &arrpf; //方式一
auto arrpfc = &arrpf; //方式二
//調用函數fb,以下幾種方式等效
int x = 5;
double y = fb(x);
double y = arrpf[1](x);
double y = (*arrpf[1])(x);
double y = (*(arrpf+1))(x);
double y = (**(arrpf+1))(x);
double y = arrpfb[1](x);
double y = (*arrpfb[1])(x);
double y = (*(arrpfb+1))(x);
double y = (**(arrpfb+1))(x);
double y = (*arrpfc)[1](x);
double y = (*(*arrpfc)[1])(x);
double y = (*(*arrpfc+1))(x);
double y = (**(*arrpfc+1))(x);
//應用指針算術時單位1表示的位元組數(32系統)
cout << int(arrpf+1)-int(arrpf); //結果為4
cout << int(&arrpf[0]+1)-int(&arrpf[0]);//結果為4
cout << int(&arrpf+1)-int(&arrpf); //結果為16
cout << int(arrpfb+1)-int(arrpfb); //結果為4
cout << int(arrpfc+1)-int(arrpfc); //結果為16
//應用sizeof()獲得記憶體量大小(32系統)
cout << sizeof(arrpf); //結果為16
cout << sizeof(&arrpf[0]);//結果為4
cout << sizeof(&arrpf); //結果為4
cout << sizeof(arrpf[0]); //結果為4
cout << sizeof(arrpfb); //結果為4
cout << sizeof(arrpfc); //結果為4
3 使用 typedef 進行簡化
可將 typedef
關鍵字用於函數指針類型,簡化程式的編寫,如下所示,此時 p_fun
就是函數指針類型 double (*)(int)
的別名,上述數組以及指針聲明可採用以下等效形式。
//指定函數指針別名
typedef double (*p_fun)(int);
//聲明並初始化函數指針數組,與前面等效
p_fun arrpf[4] = {fa,fb,fc,fd};
//聲明並初始化指向函數指針數組第一個元素的指針,與前面等效
p_fun* arrpfb = &arrpf[0];
//聲明並初始化指向整個函數指針數組的指針,與前面等效
p_fun (*arrpfc)[4] = &arrpf;
本文作者:木三百川
本文鏈接:https://www.cnblogs.com/young520/p/16691042.html
版權聲明:本文系博主原創文章,著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請附上出處鏈接。遵循 署名-非商業性使用-相同方式共用 4.0 國際版 (CC BY-NC-SA 4.0) 版權協議。