int * (*ptr)()怎麼理解(指向函數的指針)

先來分析一下int * (*ptr)()

1.由於小括號的運算級比較高,結合方法又是自左向右,所以先運算(*ptr),表明定義了一個指針ptr
2.接下來再運算最右邊的小括號(),表明是一個函數
3.接下平再運算* (*ptr)(),表明函數的返回值是一個指針
4.那麼int * (*ptr)()表明定義了一個指針變量ptr,它指向一個沒有參數,並且返回值是一個整型指針的函數。
這就叫做指向函數的指針,雖然以前聽人說大多都是在回調函數中用,但是一直感覺和普通函數每什麼區別,今天看了一個博客算是多多少收懂了一下,下面的博文有點長,不過如果你看懂了相信收貨一定會不小的(起碼我懂了回調函數到底是怎麼一回事~~)。

博文原址http://blog.csdn.net/hzyong_c/article/details/7464202

首先,先介紹一下指向函數的指針

函數指針在C/C++編程中使用的廣泛性,而對於一些初級編程者來說對函數指針的使用或許有些迷惑,而一旦在適當的時候使用了函數指針,會使代碼簡潔有力。本篇介紹的是函數指針的基礎部分,函數指針複雜的應用將在下一篇介紹。

一  指向普通函數的指針

先來看一個函數:

[cpp] view plain copy
  1. int Sum(int a, int b)  
  2. {  
  3.   return a + b;  
  4. }  

這個函數,調用方式可以如

Sum(1, 2);

若要表示函數的指針,可以用&Sum,也可以將Sum前邊的地址操作符&去掉,對於普通函數,地址操作符&是可選的

下面介紹函數指針變量和函數指針類型: 

1.  函數指針變量

[cpp] view plain copy
  1. int (*FnName)(intint);           // 聲明一個函數指針,可以將FnName理解爲新定義的變量  
  2. FnName = ∑             // 將Sum函數的地址賦給它  
  3. (*FnName)(3, 5);           // 和調用Sum(3, 5)的效果是一樣的  

第1行聲明瞭一個函數指針變量,如果有疑問,可以將FnName理解爲一個新定義的變量。函數指針變量的聲明格式:

返回類型*函數指針變量)(參數列表);

第2行將Sum函數指針賦給它,注意,只有兩個函數指針參數類型,返回值類型完全相同纔可以賦值,注意修飾符const,&等不同也會導致賦值失敗。

第3行是調用,調用格式:

*函數指針變量)(實參列表); 

2.  函數指針類型

前面介紹了函數指針變量的聲明,那麼函數指針類型如何聲明呢?

在函數指針聲明前面加個typedef就成了函數指針類型定義。
[cpp] view plain copy
  1. typedef int (*FnType)(intint);   // 聲明一個函數指針類型  
  2. FnType fb = ∑                   // 定義一個FnType類型的變量,並賦值  
  3. (*fb)(3, 5);                        // 函數調用  

第1行聲明函數指針的類型,FnType便是新聲明的類型,它是函數指針的類型

第2行定義一個FnType類型的變量,並將Sum函數地址賦值給它。

第3行是函數調用。 

前面已經瞭解了函數指針的變量和類型,看下面的代碼加深下理解:

[cpp] view plain copy
  1. int Sum(int a, int b)  
  2. {  
  3.   return a + b;  
  4. }  
  5.   
  6. typedef int (*FnType)(intint);  
  7. int Fun1(FnType ft, int x, int y)  
  8. {  
  9.   return (*ft)(x, y);  
  10. }  
  11. // 函數指針可以定義在參數列表中,在函數體內使用  
  12. int Fun2(int (*fn)(intint), int x, int y)  
  13. {  
  14.   return (*fn)(x, y);    
  15. }  
  16.   
  17. int main()  
  18. {  
  19.   cout << Fun1(&Sum, 2, 3) << " ";  // 輸出 5  
  20.   cout << Fun2(&Sum, 3, 4) << "\n"// 輸出 7  
  21.   return 0;  
  22. }  

關於普通函數指針的學習就到這裏吧,簡單吧:),下面就來學習類的成員函數的指針。 

二 指向類成員函數的指針

先看下面這個類:

[cpp] view plain copy
  1. class Num  
  2. {  
  3. public:  
  4.   Num(){n_ = 0;}  
  5.   void Inc(int n);  
  6.   void Dec(int n);  
  7.   static int Sub(int a, int b);  
  8. private:  
  9.   long n_;  
  10. };  

這個類中有普通成員函數,也有靜態成員函數,無論哪種函數,函數指針表示方式都是:

&類名::函數名

如Num類三個成員函數的指針分別是:

&Num::Inc;

&Num::Dec;

&Num::Sub;

1.  指向普通成員函數的指針

 聲明一個指向類成員函數的指針時需要用到::*符號,左邊是類名,右邊是成員函數指針名:

返回類型 類名::*成員函數指針(參數列表);

調用的時候要用到.*或->*,左邊是類對象的引用或指針,右邊是成員函數指針:

(對象名.* 成員函數指針)(實參);

(對象指針->* 成員函數指針)(實參); 

代碼示例:

[cpp] view plain copy
  1. int main()  
  2. {  
  3.   Num obj;  
  4.   void (Num::*mf)(int);    // 聲明指向成員函數的指針 mf  
  5.   mf = &Num::Inc;           // 賦值    
  6.   (obj.*mf)(1);             // 調用  
  7.   
  8.   // 成員函數的指針類型  
  9.   typedef void (Num::*mt)(int);  
  10.   mt fn = &Num::Dec;  
  11.   (obj.*fn)(2);   
  12.   
  13.   return 0;  
  14. }  

注意上面,Sub靜態成員函數,其指針聲明跟非靜態成員函數不一樣,下面來看靜態成員函數的指針。 

2. 指向靜態函數的指針
[cpp] view plain copy
  1. int (*smf)(int a, int b); // 注意寫法  
  2. smf = &Num::Sub;  
  3. cout << (*smf)(6, 7);        // 調用方式跟上一節講的普通函數調用方式一樣  

可以看到,靜態成員函數指針變量、類型聲明與普通函數一致。 

3. 指向虛函數的指針

先上代碼:

[cpp] view plain copy
  1. class Base{  
  2. public:  
  3.   virtual void F() const  
  4.   {  
  5.     cout << "I am the Base\n";  
  6.   }  
  7.   
  8.   typedef void (Base::*FnPtr)() const;  
  9. };  
  10.   
  11. class Derived : public Base{  
  12. public:  
  13.   virtual void F() const  
  14.   {  
  15.     cout << "I am the Derived\n";  
  16.   }  
  17. };  
  18.   
  19. int main()  
  20. {  
  21.   Base::FnPtr fp = &Base::F;  
  22.   Base base;  
  23. (base.*fp)();  
  24.   Derived derived;  
  25.   (derived.*fp)();  
  26.   
  27.   return 0;  
  28. }  

輸出結果:

I am theBase

I am theDerived 

可見,虛函數的指針調用結果跟直接調用虛函數效果一樣,虛函數的指針指向的函數地址是對象動態綁定的函數地址。

接下來,介紹一下函數指針在回調函數的應用

模板類,該類擁有2個成員,一個是對象指針,一個是成員函數,成員函數必須無參,無返回值。

[cpp] view plain copy
  1. struct CallbackAction {  
  2.   virtual void Execute() = 0;  
  3.   virtual ~CallbackAction() {}  
  4. };  
  5.   
  6. template <class OBJECT, class METHOD>  
  7. struct CallbackMethodAction : public CallbackAction {  
  8.   OBJECT  *object;  
  9.   METHOD   method;  
  10.   
  11.   void Execute() { (object->*method)(); }  
  12.   
  13.   CallbackMethodAction(OBJECT *object, METHOD method) : object(object), method(method) {}  
  14. };  

爲使用起來方便,進一步封裝。

[cpp] view plain copy
  1. class Callback{  
  2. public:  
  3.   explicit Callback(CallbackAction  *newaction) { action = newaction; }  
  4.   Callback() { action = NULL; }  
  5.   ~Callback();  
  6.   Callback(const Callback& c);  
  7.   Callback& operator=(const Callback& c);    
  8.   void Execute() const    { if(action) action->Execute(); }  
  9.   void operator()() const { Execute(); }  //這裏重寫了()
  10.   
  11. private:  
  12.   CallbackAction *action;  
  13. };  
  14.   
  15. Callback::Callback(const Callback& c)  
  16. {  
  17.   action = c.action;  
  18. }  
  19.   
  20. Callback::~Callback()  
  21. {  
  22. }  
  23.   
  24. Callback& Callback::operator=(const Callback& c)  
  25. {  
  26.   action = c.action;  
  27.   return *this;  
  28. }  

爲調用方便,再增加一個接口函數,注意,這裏進行了new操作,沒有delete,會造成內存泄露,本例沒有處理內存問題,解決這個問題,可以再Callback類裏添加計數器,管理指針。

[cpp] view plain copy
  1. template <class OBJECT, class METHOD>  
  2. Callback callback(OBJECT *object, void (METHOD::*method)()) {  
  3.   return Callback(new CallbackMethodAction<OBJECT, void (METHOD::*)()>(object, method));  
  4. }  

看一下如何應用

[cpp] view plain copy
  1. class Girl  
  2. {  
  3. public:  
  4.   void Shopping()  
  5.   {  
  6.     cout << "I want to shopping" << endl;  
  7.     WhenShopping();  
  8.   }  
  9.   
  10.   Callback WhenShopping;  
  11. };  
  12.   
  13. class Boy  
  14. {  
  15. public:  
  16.   void Bind(Girl* girl)  
  17.   {  
  18.     girl->WhenShopping = callback(this, &Boy::OnShopping);  //這裏就是指                                                           //向函數的指針
  19.   }  
  20.   
  21. private:  
  22.   void OnShopping()   {cout << "I know she is shopping" << endl;}  
  23. };  

客戶端調用

[cpp] view plain copy
  1. void main()  
  2. {  
  3.   Girl girl;  
  4.   Boy boy;  
  5.   boy.Bind(&girl);  //這裏可以看出回調的端倪,其實回調是在綁定的時候把要響應的對象值賦給調用的對象,當調用對象遇到重載後的括號()就會執行響應的動作
  6.   
  7.   girl.Shopping();  
  8. }  

輸出結果:

I want to shopping

I know she is shopping

上面的的代碼只是個callback使用的雛形,沒有處理內存問題和由const修飾的參數問題,直接使用會有內存泄露。另外,如果需要帶參數的函數指針類型,需要再擴展。 

//下面的我也沒看過了。。。。。。。。。。。。

下面是帶1個參數和帶2個參數的函數指針類型的應用,更多參數的函數指針這裏就不再展示了。

[cpp] view plain copy
  1. template <class P1>  
  2. struct Callback1Action {  
  3.   virtual void Execute(P1 p1) = 0;  
  4.   virtual ~Callback1Action() {}  
  5. };  
  6.   
  7. template <class OBJECT, class METHOD, class P1>  
  8. struct Callback1MethodAction : public Callback1Action<P1> {  
  9.   OBJECT  *object;  
  10.   METHOD   method;  
  11.   
  12.   void Execute(P1 p1) { (object->*method)(p1); }  
  13.   
  14.   Callback1MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {}  
  15. };  
  16.   
  17. template <class P1>  
  18. class Callback1{  
  19. public:  
  20.   explicit Callback1(Callback1Action <P1> *newaction) { action = newaction; }  
  21.   Callback1() { action = NULL; }  
  22.   ~Callback1();  
  23.   
  24.   Callback1& operator=(const Callback1& c);  
  25.   Callback1(const Callback1& c);  
  26.   
  27.   void Execute(P1 p1) const      { if(action) action->Execute(p1); }  
  28.   void operator()(P1 p1) const   { Execute(p1); }  
  29.   
  30. private:  
  31.   Callback1Action<P1> *action;  
  32. };  
  33.   
  34. template <class P1>  
  35. Callback1<P1>& Callback1<P1>::operator=(const Callback1& c)  
  36. {  
  37.   action = c.action;  
  38.   return *this;  
  39. }  
  40.   
  41. template <class P1>  
  42. Callback1<P1>::Callback1(const Callback1& c)  
  43. {  
  44.   action = c.action;  
  45. }  
  46.   
  47. template <class P1>  
  48. Callback1<P1>::~Callback1()  
  49. {  
  50. }  
  51.   
  52. // 接口函數  
  53. template <class OBJECT, class METHOD, class P1>  
  54. Callback1<P1> callback(OBJECT *object, void (METHOD::*method)(P1 p1)) {  
  55.   return Callback1<P1>(new Callback1MethodAction<OBJECT, void (METHOD::*)(P1 p1), P1>(object, method));  
  56. }  

[cpp] view plain copy
  1. template <class P1, class P2>  
  2. struct Callback2Action {  
  3.   virtual void Execute(P1 p1, P2 p2) = 0;  
  4.   virtual ~Callback2Action() {}  
  5. };  
  6.   
  7. template <class OBJECT, class METHOD, class P1, class P2>  
  8. struct Callback2MethodAction : public Callback2Action<P1, P2> {  
  9.   OBJECT  *object;  
  10.   METHOD   method;  
  11.   
  12.   void Execute(P1 p1, P2 p2) { (object->*method)(p1, p2); }  
  13.   
  14.   Callback2MethodAction(OBJECT *object, METHOD method) : object(object), method(method) {}  
  15. };  
  16.   
  17. template <class P1, class P2>  
  18. class Callback2{  
  19. public:  
  20.   explicit Callback2(Callback2Action <P1, P2> *newaction) { action = newaction; }  
  21.   Callback2() { action = NULL; }  
  22.   ~Callback2();  
  23.   
  24.   Callback2& operator=(const Callback2& c);  
  25.   Callback2(const Callback2& c);  
  26.   
  27.   void Execute(P1 p1, P2 p2) const     { if(action) action->Execute(p1, p2); }  
  28.   void operator()(P1 p1, P2 p2) const  { Execute(p1, p2); }  
  29.   
  30. private:  
  31.   Callback2Action<P1, P2> *action;  
  32. };  
  33.   
  34. template <class P1, class P2>  
  35. Callback2<P1, P2>& Callback2<P1, P2>::operator=(const Callback2& c)  
  36. {  
  37.   action = c.action;  
  38.   return *this;  
  39. }  
  40.   
  41. template <class P1, class P2>  
  42. Callback2<P1, P2>::Callback2(const Callback2& c)  
  43. {  
  44.   action = c.action;  
  45. }  
  46.   
  47. template <class P1, class P2>  
  48. Callback2<P1, P2>::~Callback2()  
  49. {  
  50. }  
  51.   
  52. template <class OBJECT, class METHOD, class P1, class P2>  
  53. Callback2<P1, P2> callback(OBJECT *object, void (METHOD::*method)(P1 p1, P2 p2)) {  
  54.   return Callback2<P1, P2>(new Callback2MethodAction<OBJECT, void (METHOD::*)(P1 p1, P2 p2), P1, P2>(object, method));  
  55. }  

應用代碼

[cpp] view plain copy
  1. class Girl  
  2. {  
  3. public:  
  4.   void Shopping()  
  5.   {  
  6.     cout << "I want to shopping" << endl;  
  7.     WhenShopping();  
  8.   
  9.     WhenBuy("fruits");  
  10.   
  11.     WhenBuy("chocolate");  
  12.   
  13.     WhenPay(20, 16);  
  14.   }  
  15.   
  16.   void Swimming()  
  17.   {  
  18.     cout << "I want to swimming" << endl;  
  19.     WhenSwimming();  
  20.   }  
  21.   
  22.   Callback WhenShopping;  
  23.   Callback WhenSwimming;  
  24.   Callback1<string> WhenBuy;  
  25.   Callback2<intint> WhenPay;  
  26. };  
  27.   
  28. class Boy  
  29. {  
  30. public:  
  31.   void Bind(Girl* girl)  
  32.   {  
  33.     girl->WhenShopping = callback(this, &Boy::OnShopping);  
  34.     girl->WhenSwimming = callback(this, &Boy::OnSwimming);  
  35.     girl->WhenBuy = callback(this, &Boy::OnBuy);  
  36.     girl->WhenPay = callback(this, &Boy::OnPay);  
  37.   }  
  38.   
  39. private:  
  40.   void OnShopping()   {cout << "I know she is shopping" << endl;}  
  41.   void OnSwimming()   {cout << "I know she is swimming" << endl;}  
  42.   void OnBuy(string thing) {cout << "She buy " << thing << endl;}  
  43.   void OnPay(int a, int b) {cout << "She pay " << a << " " << b << endl;}  
  44. };  
發佈了88 篇原創文章 · 獲贊 28 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章