zoukankan      html  css  js  c++  java
  • 回调函数

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






  • 相关阅读:
    ASP.NET MVC 3: Razor中的@:和语法
    如何设置VS的代码智能提示
    七次
    不知不觉
    一切一切
    什么是喜欢
    Oracle的substr函数简单用法与substring区别
    前端必读:浏览器内部工作原理(转载)
    sublime text 插件安装 Mac版的
    一个随机上翻的小效果
  • 原文地址:https://www.cnblogs.com/polly333/p/4498406.html
Copyright © 2011-2022 走看看