函數指針
- 函數指針指向的是函數而不是對象。和其他指針一樣,函數指針指向某種特定的類型。函數的類型由他的返回類型和形參類型共同決定,而與函數的名字無關。
//比較兩個string對象的長度
bool lengthCompare(const string &,const string &);
- 要想聲明一個可以指向該函數的指針,只需要指針替換函數的名字即可
- pf的名字之前有一個* ,因此pf是指針;右側是形參的列表,表示pf指向的是函數;觀察左側,發現函數的返回數值是bool類型的。因此,pf就是一個指向函數的指針,其中該函數的參數是兩個const string的引用,返回的是bool類型。
//pf指向一個函數,該函數的參數是兩個const string的引用,返回的數值是bool類型
bool (*pf)(const string &,const string &);//未初始化
- *pf兩端的括號不可以省略,如果沒有這對括號,則pf是一個返回數值為bool的指針的函數
//聲明一個名為pf的函數,該函數返回bool *
bool *pf(const string &,const string &);//未初始化
使用函數指針
- 當把函數的名字作為一個數值進行使用的時候,該函數會自動地轉化成指針。
//例如,按照如下的形式將lengthCompare的地址賦值給pf
//pf = lengthCompare; //pf指向名字為lengthCompare的函數
//pf = &lengthCompare;//等價的賦值語句,取地址符的符號是可選的
- 還可以直接使用指向函數的指針調用該函數,而不需要提前解引用指針
bool b1 = pf("hello","goodbye"); //調用lengthCompare函數
bool b2 = (*pf)("hello","goodbye");//一個等價的調用
bool b3 = lengthCompare("hello","goodbye");//一個等價的調用
- 指向不同函數類型的指針之間不存在轉換的規則,但是我們可以為函數指針賦值一個nullptr或者數值為0的整型常量的表達式,表示這個指針沒有指向任何一個函數
重載函數的指針
- 當使用重載函數的時候,上下文必須界定該選用哪個函數。如果定義了指向重載函數的指針
void ff(int *);
void ff(unsigned int);
void (*pf1)(unsigned int) = ff;//pf1指向了ff(unsigned int)
函數的指針形參
- 和數組類似,雖然不可以定義函數類型的形參,但是形參可以是指向函數的指針。此時形參看起來是函數的類型,實際上卻是當成指針來使用
?
//第三個形參是函數類型,他會自動的轉換成指針
void useBigger(const string &s1,const string &s2,bool pf(const string &,const string &));
//等價的聲明:顯式地將形參定義成指向函數的指針
void useBigger(const string &s1,const string &s2,bool (*pf)(const string &,const string &));
//可以把函數作為實參的使用,此時他會自動的轉化成指針
useBigger(s1,s2,lengthCompare)
- 可以使用類型的別名和decltype來簡化使用函數指針的代碼
//Func和Func2是函數的類型
typedef bool Func(const string & ,const string &);
typedef decltype(lengthCompare) Func2; //等價的類型
//Funcp和Funcp2是指向函數的指針
typedef bool (*Funcp)(const string & ,const string &);
typedef decltype(lengthCompare) *Funcp2; //等價的類型
- decltype返回函數的類型,不會將函數的類型自動轉化成為指針類型。因為,decltype的類型是函數類型,因此只有在前面加上*,才可以得到指針。
//usingBigger的等價聲明,其中使用了類型的別名
void useBigger(const string &s1,const string &s2,Func);
void useBigger(const string &s1,const string &s2,Func);
- 這兩個語句聲明的是同一個函數,在第一句中,編譯器自動的將Func表示的函數類型轉化為指針
返回指向函數的指針
- 和數組類似,不能返回一個函數,但是可以返回一個指向函數的類型的指針。
- 必須將返回的類型寫成指針的形式,編譯器不會自動的將函數的返回類型當成對應的指針類型進行處理。
- 要想聲明一個返回函數指針的函數,最簡單的方法是使用類型別名
using F = int(int*,int); //F是函數類型,不是指針using PF = int(*)(int *,int);//PF是指針類型
- 和函數的形參一樣,返回的類型不會自動地轉化成指針。必須顯示將返回類型指定為指針。
PF f1(int); //正確,PF是指向函數的指針,f1返回指向函數的指針
F f1(int); //錯誤,F是函數的類型,f1不可以返回一個函數
F *f1(int); //正確,顯示的指定返回的類型是指向函數的指針
- 也可以直接使用下面的形式直接聲明f1? ?int(*f1(int))(int *,int);
- 按照由內達外的形式閱讀這條語句,f1有形參列表,所以f1是一個函數;f1前面有*,所以f1返回的是一個指針,指針的類型本身也包含了形參的列表,因此指針指向函數,該函數的返回類型是int。
- 還可以使用尾置返回的類型的方式來聲明一個返回函數指針的函數 auto f1(int) -> int (*)(int *,int);
將auto和decltype用于函數指針類型
- 如果明確知道返回的函數是哪一個,就可以使用decltype簡化書寫函數指針返回類型的過程。
- 假定有兩個函數,返回的類型都是string::size_type,并且各有兩個const string&類型的形參,編寫第三個函數,接收一個string類型的參數,返回一個指針,這個指針指向前兩個函數中的一個。
string::size_type sumLength(const string &,const string &);string::size_type largerLength(const string &,const string &);//根據形參的取值,編寫的getFcn函數返回指向上面函數的其中一個decltype(sumLength) * getFcn(const string &);
- 聲明getFcn唯一需要注意的地方是,牢記將decltype函數作用于某一個函數的時候,返回的是函數的類型而不是指針類型。因此,只有顯示地加上 * 表示需要返回的是指針,而不是函數的本身。