回调总结

    在网上也看了不少相关的资料,总觉得少了些什么,于是自己动手,看能不能结合自己的经验,通俗易懂地描绘下。不对和不足之处请大家共同纠正。
一、函数调用类型
    假定有2个模块,A和B。
    1、同步调用
        这个最基础了,就是a.func直接调用b.func。没什么好说的。
    
    2、同步回调(采纳很多网友的说法,主要是为了有别于异步回调)
        此类型个人感觉多用于实现"多样(态)化",比如网上常见的f_cmp。
        此流程为A->B->A,最终的 "多样(态)化"实现都是在A模块。
          A模块给函数指针pfunc赋值(没有用注 册/ 的,区别见异步调用), B模块使用即可。
          可以从一般的形参角度来看此pfunc。
     
    3、异步回调
        此类型是很多网友都没有说通透的。我来试一试。
        此流程A<-B。怎么理解呢,这里就要涉及 注册/关联。在A模块中把a.func和B模块中的b.func关联起来。
        A中
        {
            B.attach(pafunc,...);    // pafunc为指向a.func的函数指针
            ......
               B.disattach(,,...);  
        }
        B中
        {
             B.attach(pafunc,...)
            {
                b.func = a.func;     
            }
            b.fun()
            {

            }
        }
        这个就是最通用的dispatch机制。假如A为GUI中的Pages,B为GUI中的Mouse。
        Mouse获取Message后 dispatch给Pages。

        先以产品级的GUI来描述。
        
        //GUI同步回调例子
        
        /*按键处理函数*/
        typedef int (CGui::*KeyHandlerFuncPtr)(key_enum key, void *para);
        KeyHandlerFuncPtr pKeyHander = NULL;

        int CGui::HandleKey(key_enum  key, void *para)
        {
               if(pKeyHander)
               {
                    return (this->*pKeyHander)(key, para);
               }
               return -1;
        }
        //在线程中获取key
        void CGui::GuiThreadBody()
        {
                ......
                 key_enum k eyval;
                    if( k eyval != KVT_INVALID)
                    {
                         HandleKey( k eyval , NULL);
                    }
                ......
        }

        //初始化第一个 pKeyHander,也就是开机后第一个界面的handler
         pKeyHander   = NULL;
         void CGui::InitGui()
        {
            ......
            pKeyHander = &CGui::Page0Handler;
            ......
        }

        //后续的 handler在Page0Handler ()中赋值
        int CGui:: Page0Handler(key_enum  key, void *para)
        {
            ......
            if(page1)
            {
                   pKeyHander = &CGui::Page1Handler;
            }
            ......
        }
        //在page1中也可以返回page0
          int CGui:: Page1Handler(key_enum  key, void *para)
        {
            ......
            if(page0)
            {
                   pKeyHander = &CGui::Page0Handler;
            }
            ......
        }

         //GUI异步回调例子
        void CMOUS::MouseThreadBody()
        {
            SignalKey(key,pos,void*);
        }

        int  CMOUS::Attach(pfunc)
        {
             SignalKey =  Page:InputKey;
        }

        int Page:InputKey()
        {}

        int Page:Page0()
        {
            g_Mouse.attach(pInputKey);       //attach
        }

        大家可以参考下SDL的Audio的回调,这个也是异步的。
        App中
        {
             static int stream_component_open(VideoState *is, int stream_index)
            {
                ......
                SDL_AudioSpec wanted_spec;
                wanted_spec.callback = sdl_audio_callback;      //attach
                if (SDL_OpenAudio(&wanted_spec, &spec) < 0)
                {}
                ......  
             }
             
             void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
             {

             }
        }
    
        SDL中
        {
            在code中跟踪 SDL_AudioSpec,可以看到App.  sdl_audio_callback()中的* stream是由SDL传给APP中的
        }
        
        一个小小的trick,当你在你的app中没有找到某函数的显示调用(但确实调用了),而且其形参也"来路不明"
       时,你就要怀疑此函数是否是异步调用了。

最后一句话,回调讲完了,C++"委托"还会远么。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值