首页 > 代码库 > C++之------回调函数

C++之------回调函数

 

 

 一:What?(什么是回调函数)

 


 

  

   回调函数图文讲解

    

  

 

 

 

    谓回调,就是客户程序C调用服务程序S中的某个函数A,然后S又在某个时候反过来调用C中的某个函数B,对于C来说,这个B便叫做回调函数。

 例如Win32下的窗口过程函数就是一个典型的回调函数。

           一般说来,C不会自己调用B,C提供B的目的就是让S来调用它,而且是C不得不提供。由于S并不知道C提供的B叫甚名谁,所以S会约定B的接

口规范(函数原型),然后由C提前通过S的一个函数R告诉S自己将要使用B函数,这个过程称为回调函数的注册,R称为注册函数。

 

 

再看看回调函数的庐山面目

下面的SmartOS中Zegbe通讯函数回调的注册  (由于是公司商业代码,所以不贴逻辑代码)

 1 virtual void Register(TransportHandler handler, void* param = NULL) 2     { 3         if(handler) 4         { 5             _handler = handler; 6             _param = param; 7  8             if(!Opened) Open(); 9         }10         else11         {12             _handler = NULL;13             _param = NULL;14         }15     }16 17 protected:18     virtual bool OnOpen() { return true; }19     virtual void OnClose() { }20     virtual bool OnWrite(const byte* buf, uint len) = 0;21     virtual uint OnRead(byte* buf, uint len) = 0;22 23     // 是否有回调函数24     bool HasHandler() { return _handler != NULL; }25 26     // 引发数据到达事件27     virtual uint OnReceive(byte* buf, uint len)28     {29         if(_handler) return _handler(this, buf, len, _param);30 31         return 0;32     }

    这个是整个通讯流类里面的回调函数使用

 

      下面举个例子说明回调函数的过程:

      ①:  比喻我打电话向你请教问题,当然是个难题      

      ②:  你一时也想不出解决方法,我又不能拿着电话在那里傻等,于是我们约定:等你想出办法后打手机通知我,这样,我就挂掉电话办其它事情去了。   (注册回调函数)

      ③:  XX分钟,我的手机响了,你兴高采烈的说问题已经搞定,应该如此这般处理。故事到此结束。   (回调函数操作)

 

          其中,你后来打手机告诉我结果便是一个“回调”过程;我的手机号码必须在以前告诉你,这便是注册回调函数;我的手机号码应该有效并且手机能够接收到你的呼叫,这是回调函数必须符合接口规范。

 

   回调函数的编程特点是:“异步+回调 ”

 

 

二   Why? ( 回调函数实现过程)


 

 

 

  1     2   3   1 //def.h     4   2 #include <iostream>     5   3 #include <stdio.h>     6   4 using namespace std;    7   5     8   6 typedef enum    9   7 {   10   8     CB_MOVE = 0,    //      11   9     CB_COMEBACK,    //    12  10     CB_BUYEQUIIP,   //    13  11 }cb_type;   14  12    15  13 typedef void(*cb_func)(void *);   16  14    17  15 class CCommu //模块类    18  16 {   19  17 public:   20  18     CCommu()   21  19     {   22  20         memset(func_list, 0, sizeof(cb_func) *(CB_BUYEQUIIP +1));   23  21         memset(func_args, 0, sizeof(void *) *(CB_BUYEQUIIP +1));   24  22     }   25  23    26  24     int reg_cb(cb_type type, cb_func func, void *args = NULL)//注册回调函数     27  25     {   28  26         if(type <= CB_BUYEQUIIP)    29  27         {   30  28             func_list[ type ] = func;   31  29             func_args[type] = args;   32  30             return 0;   33  31         }   34  32     }   35  33 public:   36  34     cb_func func_list[CB_BUYEQUIIP + 1] ;   //函数指针数组    37  35     void * func_args[CB_BUYEQUIIP +1];   38  36 };   39  37  40  38  41  39  42  40  43  41 //Gamestart.h 44  42 #include "def.h" 45  43  46  44 class CGameStart 47  45 { 48  46  49  47 public: 50  48     CGameStart(); 51  49     ~CGameStart(); 52  50     void Init(); 53  51     void run(); 54  52     void Execute(); 55  53      56  54     //一些回调函数 57  55     void static Move(void *args); 58  56     void static Comeback(void *args); 59  57     void static Buyequip(void *args); 60  58  61  59 public: 62  60     CCommu *pCommu; 63  61  64  62 }; 65  63  66  64  67  65  68  66 //Gamestart.cpp    69  67 #include "Gamestart.h"    70  68    71  69 CGameStart::CGameStart():pCommu(NULL)   72  70 {}   73  71    74  72 void CGameStart::Init() //初始化的时候,注册回调函数     75  73 {   76  74     pCommu  = new CCommu;   77  75     pCommu ->reg_cb(CB_MOVE, Move , this);   78  76     pCommu->reg_cb (CB_COMEBACK, Comeback,this );   79  77 }   80  78    81  79 void CGameStart::run()   82  80 {   83  81     Init();   84  82 }   85  83    86  84 void CGameStart::Execute()   87  85 {   88  86     cout<<"callback funciton is running"<<endl;   89  87    90  88 }   91  89 CGameStart::~CGameStart()   92  90 {   93  91     if(pCommu != NULL)   94  92     {   95  93         delete pCommu;   96  94         pCommu = NULL;   97  95     }   98  96 }   99  97   100  98 void CGameStart::Move(void *args)  101  99 {  102 100     CGameStart *pGame  = (CGameStart *)args;  103 101     pGame -> Execute();  104 102 }  105 103 void CGameStart::Comeback(void *args)   106 104 {  107 105     //char *str = (char *)args;   108 106     //cout << str <<endl;   109 107 }  110 108 111 109 112 110 113 111 114 112 115 113 116 114 //main.cpp117 115 #include "Gamestart.h"   118 116   119 117 120 118 int main()  121 119 {  122 120   123 121     CGameStart *pGame = new CGameStart;  124 122     pGame -> run();  125 123     if(pGame->pCommu->func_list[CB_MOVE] != NULL)//回调函数的触发   126 124     {  127 125         pGame->pCommu->func_list[CB_MOVE](pGame->pCommu->func_args[CB_MOVE]);  128 126     }  129 127     return 0;  130 128 }  

 

时代在不断进步,SDK不再是古老的API接口,C++面向对象编程被广泛的用到各种库中,因此回调机制也可以采用C++的一些特性来实现。
 通过前面的讲解,其实我们不难发现回调的本质便是:SDK定义出一套接口规范,应用程序按照规定实现它。这样一说是不是很简单,

想想我们C++中的继承,想想我们亲爱的抽象基类......于是,我们得到以下的代码:

 1 /// sdk.h 2 #ifndef __SDK_H__ 3 #define __SDK_H__ 4  5 class Notifier // 回调类,应用程序需从此派生 6 { 7 public: 8  virtual ~Notifier() { } 9  virtual void got_answer(const char* answer) = 0; // 纯虚函数,用户必须实现它10 };11 12 class Sdk // Sdk提供服务的类13 {14 public:15  Sdk(Notifier* pnotifier); // 用户必须注册指向回调类的指针16  void help_me(const char* question);17 protected:18  void do_it();  19 protected:20  Notifier* m_pnotifier; // 用于保存回调类的指针21 };22 23 #define//__SDK_H__24 25 /// sdk.cpp26 #include "sdk.h"27 #include "windows.h"28 #include <iostream>29 using namespace std;30 31 Sdk::Sdk(Notifier* pnotifier) : m_pnotifier(pnotifier)32 {33 }34 35 void Sdk::help_me(const char* question)36 {37  cout << "help_me: " << question << endl;38  do_it(); 39 }40 41 void Sdk::do_it()42 {43  cout << "thinking..." << endl;44  Sleep( 3000 );45  cout << "think out." << endl;46  cout << "call him." << endl;47  m_pnotifier->got_answer( "2." );48 }49 50 /// app.cpp51 #include "sdk.h"52 53 class App : public Notifier // 应用程序实现一个从回调类派生的类54 {55 public:56  App( const char* name ) : m_sdk(this), m_name(name) // 将this指针传入57  {58  }59  void ask( const char* question )60  {61   m_sdk.help_me( question );62  }63  void got_answer( const char* answer ) // 实现纯虚接口64  {65   cout << m_name << " got_answer: " << answer << endl;66  }67 protected:68  Sdk m_sdk;69  const char* m_name;70 };71 72 int main()73 {74  App app("ABC");75  app.ask( "1+1=?");76  return 0;77 }

 

三: When?  (什么时候使用回调)


 

 

如果你是SDK的使用者,一旦别人制定了回调机制,那么你被迫得使用回调函数,因此这个问题只对SDK设计者有意义。
 从引入的目的看,回调大致分为三种:
 1) SDK有消息需要通知应用程序,比如定时器被触发;
 2) SDK的执行需要应用程序的参与,比如SDK需要你提供一种排序算法;
 3) SDK的操作比较费时,但又不能让应用程序阻塞在那里,于是采用异步方式,让调用函数及时返回,SDK另起线程在后台执行操作,待操作完成后再将结果通知应用程序。

 

END!

参考部分网络资源

 

 

欢迎大家一起交流 ,分享程序员励志故事。   幸福的程序员 QQ群:幸福的程序员 

  

 

C++之------回调函数