C++ 程式設計/運算子/指標/函式指標
我們已經瞭解過的指標都是資料指標,函式指標(更常見的是函式指標)非常類似,並且與其他指標具有相同的特性,但它們不是指向變數,而是指向函式。建立了一個額外的間接層,作為在 C++ 中使用函數語言程式設計正規化的途徑,因為它便於呼叫從同一程式碼段在執行時確定的函式。它們允許將函式作為引數或返回值傳遞給另一個函式。
使用函式指標與任何其他函式呼叫具有完全相同的開銷,再加上額外的指標間接,並且由於要呼叫的函式僅在執行時確定,編譯器通常不會像在其他地方那樣行內函數呼叫。由於這種特性,使用函式指標可能會比使用常規函式呼叫慢得多,應該避免使用它來提高效能。
要天真地宣告一個指向函式的指標,指標的名稱必須用括號括起來,否則將宣告一個返回指標的函式。你還必須宣告函式的返回值型別及其引數。這些必須完全匹配!
考慮
int (*ptof)(int arg);
要引用的函式必須具有與指向函式的指標相同的返回值型別和相同的引數型別。函式的地址可以透過簡單地使用其名稱來分配,可以選擇在前面加上地址運算子 &。可以透過使用 ptof(<value>) 或 (*ptof)(<value>) 來呼叫函式。
所以
int (*ptof)(int arg);
int func(int arg){
//function body
}
ptof = &func; // get a pointer to func
ptof = func; // same effect as ptof = &func
(*ptof)(5); // calls func
ptof(5); // same thing.
返回一個float的函式不能由返回一個double的指標指向。如果兩個名稱相同(例如int和signed,或者typedef名稱),則允許轉換。否則,它們必須完全相同。你透過將*與變數名稱分組來定義指標,就像你對任何其他指標一樣。問題是它可能會被解釋為返回型別而不是其他型別。
使用 typedef 為函式指標型別定義型別通常更清晰;這還提供了一個地方為函式指標型別指定一個有意義的名稱
typedef int (*int_to_int_function)(int);
int_to_int_function ptof;
int *func (int); // WRONG: Declares a function taking an int returning pointer-to-int.
int (*func) (int); // RIGHT: Defines a pointer to a function taking an int returning int.
為了減少混淆,通常typedef函式型別或指標型別
typedef int ifunc (int); // now "ifunc" means "function taking an int returning int"
typedef int (*pfunc) (int); // now "pfunc" means "pointer to function taking an int returning int"
如果你typedef函式型別,你可以宣告,但不能定義具有該型別的函式。如果你typedef指標型別,你既不能宣告也不能定義具有該型別的函式。使用哪種方式是風格問題(儘管指標更流行)。
要將指標分配給函式,你只需將它分配給函式名稱。這個&運算子是可選的(它並不模稜兩可)。如果存在,編譯器將自動選擇適合指標的函式的過載版本
int f (int, int);
int f (int, double);
int g (int, int = 4);
double h (int);
int i (int);
int (*p) (int) = &g; // ERROR: The default parameter needs to be included in the pointer type.
p = &h; // ERROR: The return type needs to match exactly.
p = &i; // Correct.
p = i; // Also correct.
int (*p2) (int, double);
p2 = f; // Correct: The compiler automatically picks "int f (int, double)".
使用指向函式的指標更加簡單 - 你只需像呼叫函式一樣呼叫它。你允許使用*運算子對其進行解引用,但你不需要
#include <iostream>
int f (int i) { return 2 * i; }
int main ()
{
int (*g) (int) = f;
std::cout<<"g(4) is "<<g(4)<<std::endl; // Will output "g(4) is 8"
std::cout<<"(*g)(5) is "<<g(5)<<std::endl; // Will output "g(5) is 10"
return 0;
}