回调函数

1、什么是回调函数。

软件模块之间通信、调用总有一定的机制,从调用方式上可以分为:同步调用、异步调用和回调。同步调用的一种阻塞调用,调用方必须等待被调用方执行完毕后,才能继续执行,所以造成在执行效率的低下。异步调用是一种类似消息或者事件机制,不过它的调用方向相反,接口的服务在收到某种信息后或者发生某种事件后,会主动通知客户方(即调用客户的接口)。回调函数则是一种双向调用模式,也就是,被调用方在接口被调用是,也会调用对方的接口。(异步是单向的)。回调和异步的之间联系比较密切,通常我们有异步调用来注册回调函数,通过异步来实现信息的获取。

回调函数是一种函数或者过程,不过它是由调用方自己实现,供被调用者使用的特殊函数。在windows平台的消息机制可以看做回调函数的特例,通过系统提供的接口注册消息处理函数,从而实现接收和处理函数。

2、过程语言中的回调函数

2.1函数指针

在C语言中应用回调函数,一般是想调用者的参数列表中,传入回调函数的函数指针。比如:

void Func(char* S);//函数原型
void (pFunc)(char* s);//函数指针
下面讲一个调用例子:

typedef void(* pfun)(char *);//一位这个函数指针中指向的函数的返回值类型,以及参数类型个数,只要合适,在调用函数中都能传入。

void GetCallBack(pfun callback)
{dosomething;}

用户在调用上面的函数,需要自己实现一个pfunc类型的回调函数。比如:void Func(char *s);

然后可以调用了:GetCallBack(Func);

如果赋值了不同的值给该参数,那么调用者就将调用不同地址的函数。赋值可以在运行时,这样使你能实现动态绑定。

2.2参数调用机制

到目前为止,我们只讨论了函数指针及回调而没有去注意ANSI C/C++的编译器规范。

许多编译器有几种调用规范。如在Visual C++中,可以在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默认为_cdecl)。C++ Builder也支持_fastcall

调用规范。调用规范影响编译器产生的给定函数名,参数传递的顺序(从右到左或从左到右),堆栈清理责任(调用者或者被调用者)以及参数传递机制(堆栈,CPU寄存器等)。在回调函数中一定注意调用机制,如果调用机制出现问题,将无法有效进行调用。

将调用规范看成回调函数中重要的一部分很重要,不能用不兼容的调用规范,将地址赋值给函数指针。


__stdcall int Func(int);//被调用函数为__stdcall
void caller(__cdcel int(*ptr)(int));//调用函数以函数指针为参数,但调用规范为_cdcel.
_cdcel int (*ptr)(int) = Func;//报错.调用规范不一致。


3、面向对象的回调函数

面向对象的回调函数其调用机制与概念与以上所述是一致,关键在于面相对象,提供调用接口,这种应用更为广泛。在集成中,常常会用调用厂家的回调函数,为集成者提供接口信息及处理的完成情况。
比如:
static int __stdcall VodFileInfoCallback_xxx(const ST_VodFileInfo vodFileInfo,const ISOC_DWORDPTR dwCookie,const ISOC_STR strQueryGUID);//厂家sdk中回调函数的调用规范以及返回类型,参数类型等。
为了可以调用,在调用函数的头文件里定义自己的回调函数:
static int __stdcall VodFileInfoCallback_owner(const ST_VodFileInfo vodFileInfo,const ISOC_DWORDPTR dwCookie,const ISOC_STR strQueryGUID);//函数名称可以不同,但是调用规范,返回值类型,参数类型个数必须一致。
调用函数:(调用函数当然是从厂家中提取出来的)<pre name="code" class="html">int GetVodFileList( LONG_PTR UserID,const char * strDeviceList,ST_VodQueryFilter stQueryFilter,VodFileInfoCallback_xxx pCallBack, DWORD_PTR dwCookie );
在此函数实现时(cpp)文件,函数调用可以为:
 
 
this-> GetVodFileList( UserID, strDeviceList,stQueryFilter,VodFileInfoCallback_owner , this );//其中this代表<pre name="code" class="html">VodFileInfoCallback_owner在当前文件中进行实现,加入不是,下面讲讲。
 同时 
 
int __stdcall VodFileInfoCallback_owner(const ST_VodFileInfo vodFileInfo,const ISOC_DWORDPTR dwCookie,const ISOC_STR strQueryGUID)
{
do something;
CClassa *ptr = (CClass*)dwcookie;//定义这样的话,便可以通过ptr调用类中的成员函数以及成员变量。
}
加入回调函数: VodFileInfoCallback_owner与调用者不在同一层的话,就不能用this。而是用传下来的。
比如:class1调用class2中的函数,class2调用class3 的函数。
在class1中头文件、源文件有回调函数的定义和实现: VodFileInfoCallback_owner
而在class中用函数
int CallBack(VodFileInfoCallback_owner callback,void * puser)
{
callback(vodfileifo,puser,strqueryguid);
}
这里重点是讲puser指针的问题,其他当然要赋值,只有这样才能调用class1中回调函数。






  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值