函數指針是指向函數的指針變量。 因此“函數指針”本身首先應是指針變量,只不過該指針變量指向函數。這正如用指針變量可指向整型變量、字符型、數組一樣,這里是指向函數。如前所述,C在編譯時,每一個函數都有一個入口地址,該入口地址就是函數指針所指向的地址。有了指向函數的指針變量后,可用該指針變量調用函數,就如同用指針變量可引用其他類型變量一樣,在這些概念上是大體一致的。函數指針有兩個用途:調用函數和做函數的參數。
1 #include<stdio.h> 2 int max(int x,int y){return (x>y? x:y);} 3 int main() 4 { 5 int (*ptr)(int, int); 6 int a, b, c; 7 ptr = max; 8 scanf("%d%d", &a, &b); 9 c = (*ptr)(a,b); 10 printf("a=%d, b=%d, max=%d", a, b, c); 11 return 0; 12 }
以上來自百度百科
函數指針指向的是函數而非對象。和其他指針一樣,函數指針指向某種特定類型。函數的類型由它的返回類型和形參類型共同決定,與函數名無關:
bool length_compare(const string &, const string &);
該函數的類型是 bool(const string &, const string &);想要聲明一個指向該函數的指針,只要用指針替換函數名即可:
1 #include <iostream> 2 using namespace std; 3 4 bool leng_compare(const string &s1, const string &s2){ 5 return s1.size() > s2.size(); 6 } 7 8 int main(void){ 9 //pf指向一個函數,該函數的參數是兩個 const string 的引用,返回值是 bool 類型 10 bool (*pf) (const string &, const string &);//未初始化 11 return 0; 12 }
注意 *pf 兩端的括號必不可少的。如果不寫這對括號,則 pf 是一個返回值為 bool 指針的函數。
使用指針函數:
當我們把函數名作為一個值使用時,該函數自動地轉換成指針:
#include <iostream> using namespace std; bool leng_compare(const string &s1, const string &s2){ return s1.size() > s2.size(); } int main(void){ //pf指向一個函數,該函數的參數是兩個 const string 的引用,返回值是 bool 類型 bool (*pf) (const string &, const string &);//未初始化 pf = leng_compare;//pf指向名為 leng_compare 的函數 cout << &pf << endl; cout << *pf << endl; cout << pf << endl; pf = &leng_compare;//和上面的那條賦值語句是等價的,即取地址符是可選的 cout << &pf << endl; cout << *pf << endl; cout << pf << endl; return 0; }
此外,我們還能直接使用指向函數的指針調用該函數,無需提前解引用指針:
#include <iostream> using namespace std; bool leng_compare(const string &s1, const string &s2){ return s1.size() > s2.size(); } int main(void){ //pf指向一個函數,該函數的參數是兩個 const string 的引用,返回值是 bool 類型 bool (*pf) (const string &, const string &);//未初始化 pf = leng_compare;//pf指向名為 leng_compare 的函數 bool flag1 = pf("acfjls", "fjsl");//調用leng_compare函數 bool flag2 = (*pf)("fjlsfld", "jfs");//一個等價調用 bool flag3 = leng_compare("fjslfjs", "jfkdl");//另一個等價調用 return 0; }
指向不同函數類型的指針間不存在轉換規則。但是和往常一樣,我們可以為函數指針賦一個 nullptr 或者值為 0 的常量表達式,表示該指針沒有指向任何一個函數。
重載函數的指針:
當我們使用重載函數的指針時,上下文必須清晰地界定到底應該選用哪個函數。編譯器通過指針類型確定選用哪個函數,指針類型必須與重載漢薩中的某一個精確匹配:
1 #include <iostream> 2 using namespace std; 3 4 int gel(int* x){} 5 6 int gel(unsigned int x){} 7 8 int main(void){ 9 int cnt = gel(1);//單獨函數調用是可以不是精確匹配,只要能有最佳匹配即可 10 // int (*pf1)(int) = gel;//錯誤:形參列表不能精確匹配 11 // double (*pf2)(int*) = gel;//錯誤:和第一個gel函數返回類型不匹配,和第二個gel函數形參不匹配 12 int (*pf3)(unsigned int) = gel;//正確 13 return 0; 14 }
函數指針形參:
和數組類似,雖然不能定義函數類型的形參,但是形參可以是指向函數的指針。此時形參看起來是函數類型,實際上卻是當成指針使用:
1 #include <iostream> 2 using namespace std; 3 4 bool length_compare(const string &, const string &){} 5 6 //第三個形參是函數類型,它會自動轉換成指向函數的指針 7 void max(const string &s1, const string &s2, bool pf(const string &, const string &)){} 8 //等價聲定義,顯示地將形參定義成指向函數的指針 9 // void max(const string &s1, const string &s2, bool (*pf)(const string &, const string &)){}; 10 11 int main(void){ 12 max("fjs", "jfls", length_compare);//把函數當作為實參使用,此時它會自動地轉換成指針 13 return 0; 14 }
可以使用 typedef 定義自己的類,簡化函數使用函數指針:
1 #include <iostream> 2 using namespace std; 3 4 bool length_compare(const string &, const string &){} 5 6 // gel1 和 gel2 是等價的函數類型 7 typedef bool gel1(const string &, const string &); 8 typedef decltype(length_compare) gel2; 9 10 //gel3 和 gel4 是等價的指針類型 11 typedef bool(*gel3)(const string &, const string &); 12 typedef decltype(length_compare) *gel4; 13 14 //需要注意的是這里的 decltype 返回的是函數類型,此時不會將函數類型自動轉換成指針類型,只有在 decltype 返回結果前加上 * 才能得到指針 15 16 void max(const string &s1, const string &s2, gel1){}//編譯器自動將gel1轉換成指針類型了 17 18 // void max(const string &s1, const string &s2, gel3){}//等價聲明 19 20 int main(void){ 21 max("fjs", "jfls", length_compare);//把函數當作為實參使用,此時它會自動地轉換成指針 22 return 0; 23 }
返回指向函數的指針:
和數組類似,雖然不能返回一個函數,但是能返回指向函數類型的指針。然而,我們必須把返回類型寫成指針的形式,編譯器不會自動地將函數返回類型當成對應的指針類型處理。而想要聲明一個返回函數指針的函數,可以直接聲明,使用類型別名,尾置類型等:
1 #include <iostream> 2 using namespace std; 3 4 using gel1 = int(int*, int);//gel1是函數類型,不是指向函數的指針 5 using gel2 = int(*)(int*, int);//gel2是指向函數的指針 6 // typedef int (*gel3)(int*, int);//gel2的等價類型 7 8 // gel1 lou(int x);//錯誤:gel1是函數類型,不是指針類型 9 gel2 lou(int x); 10 gel1* lou(int x); 11 int (*lou(int x))(int *, int);//不使用類型別名,直接聲明 12 auto lou(int) -> int (*)(int *, int);//使用尾置返回類型 13 14 int main(void){ 15 return 0; 16 }
使用 decltype:
當我們明確知道返回的函數是哪一個,就能使用 decltype 簡化書寫函數指針返回類型的過程,需要注意的是 decltype 返回的不是指針,需要添加 *,這點和數組是一樣的:
1 #include <iostream> 2 using namespace std; 3 4 int gel(int *, int); 5 6 decltype(gel) *lou(int x);//注意這里的*不能落掉 7 8 int main(void){ 9 return 0; 10 }