/*--------------------CSS部分-------------------*/ /*--------------------JS部分-------------------*/

回调函数

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中回调函数。






 

posted @ 2014-08-18 14:02  bldong  阅读(422)  评论(0编辑  收藏  举报