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. };  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值