之所以想寫一篇函數指標的文章,源於函數指標在C/C++編程中使用的廣泛性,而對於一些初級編程者來說對函數指標的使用或許有些迷惑,而一旦在適當的時候使用了函數指標,會使代碼簡潔有力。本篇介紹的是函數指標的基礎部分,函數指標複雜的應用將在下一篇介紹。 一 指向普通函數的指標
先來看一個函數:
int Sum(int a, int b){ return a + b;}
這個函數,調用方式可以如
Sum(1, 2);
若要表示函數的指標,可以用&Sum,也可以將Sum前邊的地址操作符&去掉,對於普通函數,地址操作符&是可選的。
下面介紹函數指標變數和函數指標類型:
1. 函數指標變數
int (*FnName)(int, int); // 聲明一個函數指標,可以將FnName理解為新定義的變數FnName = ∑ // 將Sum函數的地址賦給它(*FnName)(3, 5); // 和調用Sum(3, 5)的效果是一樣的
第1行聲明了一個函數指標變數,如果有疑問,可以將FnName理解為一個新定義的變數。函數指標變數的聲明格式:
傳回型別(*函數指標變數)(參數列表);
第2行將Sum函數指標賦給它,注意,只有兩個函數指標參數類型,傳回值類型完全相同才可以賦值,注意修飾符const,&等不同也會導致賦值失敗。
第3行是調用,調用格式:
(*函數指標變數)(實參列表);
2. 函數指標類型
前面介紹了函數指標變數的聲明,那麼函數指標類型如何聲明呢。 在函數指標聲明前面加個typedef就成了函數指標類型定義。
typedef int (*FnType)(int, int); // 聲明一個函數指標類型FnType fb = ∑ // 定義一個FnType類型的變數,並賦值(*fb)(3, 5); // 函數調用
第1行聲明函數指標的類型,FnType便是新聲明的類型,它是函數指標的類型。
第2行定義一個FnType類型的變數,並將Sum函數地址賦值給它。
第3行是函數調用。 前面已經瞭解了函數指標的變數和類型,看下面的代碼加深下理解:
int Sum(int a, int b){ return a + b;}typedef int (*FnType)(int, int);int Fun1(FnType ft, int x, int y){ return (*ft)(x, y);}// 函數指標可以定義在參數列表中,在函數體內使用int Fun2(int (*fn)(int, int), int x, int y){ return (*fn)(x, y); }int main(){ cout << Fun1(&Sum, 2, 3) << " "; // 輸出 5 cout << Fun2(&Sum, 3, 4) << "\n"; // 輸出 7 return 0;}
關於普通函數指標的學習就到這裡吧,簡單吧:),下面就來學習類的成員函數的指標。 二 指向類成員函數的指標 先看下面這個類:
class Num{public: Num(){n_ = 0;} void Inc(int n); void Dec(int n); static int Sub(int a, int b);private: long n_;};
這個類中有普通成員函數,也有靜態成員函數,無論哪種函數,函數指標表示方式都是:
&類名::函數名
如Num類三個成員函數的指標分別是:
&Num::Inc;
&Num::Dec; &Num:: Sub;
1. 指向普通成員函數的指標
聲明一個指向類成員函數的指標時需要用到::*符號,左邊是類名,右邊是成員函數指標名:
傳回型別 類名::*成員函數指標(參數列表);
調用的時候要用到.*或->*,左邊是類對象的引用或指標,右邊是成員函數指標:
(對象名.* 成員函數指標)(實參);
或
(對象指標->* 成員函數指標)(實參);
程式碼範例:
int main(){ Num obj; void (Num::*mf)(int); // 聲明指向成員函數的指標 mf mf = &Num::Inc; // 賦值 (obj.*mf)(1); // 調用 // 成員函數的指標類型 typedef void (Num::*mt)(int); mt fn = &Num::Dec; (obj.*fn)(2); return 0;}
注意上面,Sub是靜態成員函數,其指標聲明跟非靜態成員函數不一樣,下面來看靜態成員函數的指標。 2. 指向靜態函數的指標
int (*smf)(int a, int b); // 注意寫法smf = &Num::Sub;cout << (*smf)(6, 7); // 調用方式跟上一節講的普通函數調用方式一樣
可以看到,靜態成員函數指標變數、型別宣告與普通函數一致。
3. 指向虛函數的指標
先上代碼:
class Base{public: virtual void F() const { cout << "I am the Base\n"; } typedef void (Base::*FnPtr)() const;};class Derived : public Base{public: virtual void F() const { cout << "I am the Derived\n"; }};int main(){ Base::FnPtr fp = &Base::F; Base base;(base.*fp)(); Derived derived; (derived.*fp)(); return 0;}
輸出結果:
I am theBase
I am theDerived 可見,虛函數的指標調用結果跟直接調用虛函數效果一樣,虛函數的指標指向的函數地址是對象動態綁定的函數地址。