函數指針(函數指針作為函數形參/函數類型作為函數返回類型)


函數指針是指向函數的指針變量。 因此“函數指針”本身首先應是指針變量,只不過該指針變量指向函數。這正如用指針變量可指向整型變量、字符型、數組一樣,這里是指向函數。如前所述,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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM