博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++之------回调函数
阅读量:4605 次
发布时间:2019-06-09

本文共 5961 字,大约阅读时间需要 19 分钟。

 

 

 一: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 
5 3 #include
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"<
Execute(); 104 102 } 105 103 void CGameStart::Comeback(void *args) 106 104 { 107 105 //char *str = (char *)args; 108 106 //cout << str <
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 
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群:

  

 

转载于:https://www.cnblogs.com/1hua1ye/p/3955651.html

你可能感兴趣的文章
Android中Context详解 ---- 你所不知道的Context
查看>>
8.存储过程和触发器
查看>>
NOIP模拟题——LGTB与桌子
查看>>
64位Navicat Premium安装/破解【含资源】
查看>>
事件查看器常见ID代码解释
查看>>
使用mdf和ldf附加还原SQL Server数据文件
查看>>
python函数
查看>>
Python美味食谱:1.7 将字符串逐字符或逐词反转
查看>>
LeetCode:Divide Two Integers
查看>>
ubuntu mysql INTO FILE 权限问题
查看>>
CentOs7-常用命令
查看>>
hdu1061
查看>>
layui学习--tab选项卡
查看>>
Python学习笔记四(迭代器、生成器、内置函数)
查看>>
TRIZ系列-创新原理-34-抛弃和再生部件原理
查看>>
(转)理解伽马(Gamma)
查看>>
软件的模块化开发
查看>>
HTTP 错误 404.13 - Not Found 请求筛选模块被配置为拒绝超过请求内容长度的请求。...
查看>>
UOJ.52.[UR #4]元旦激光炮(交互 思路)
查看>>
登录时,手机号邮箱号验证
查看>>