回调函数的理解

        在工作中不断的遇到和听到回调函数,但自己对回调函数一直并未尝试使用,感觉理解也不够清晰。下面摘了一些其他看起来通俗易懂的说明,先记下来,备忘。

    

     1、基础知识

所谓回调,就是模块A要通过模块B的某个函数b()完成一定的功能,但是函数b()自己无法实现全部功能,需要反过头来调用模块A中的某个函数a()来完成,这个a()就是回调函数。如下图

①约定接口规范。在模块B必须约定接口规范,也就是定义回调函数a()的函数原型

这里回调函数原型的定义最好遵循typedef void (*SCT_XXX)(LPVOID lp, const CBParamStruct& cbNode); SCT_XXX是回调函数名称,lp是回调上下文,CBParamStruct是回调参数,一般由于要回调的参数不止一个,所以定义一个结构体比较方便。

②回调函数的注册。为了让模块B知道自己将要使用的回调函数,必须有一个函数或语句来注册回调函数

注册回调函数的定义遵循void RCF_XXX(SCT_XXX pfn, LPVOID lp); RCF_XXX是注册函数名,pfn是回调函数名称(是指针),lp是回调上下文。一般在A模块初始化完B模块后调用,将A模块中定义的回调函数地址赋值给pfn,lp赋值为this。 

③在模块A中要做的事情:

首先将回调函数声明成静态的,static void  CF_XXX(LPVOID lp, const CBParamStruct& cbNode); 函数的参数必须与B模块中回调函数原型的参数保持一致。

初始化B模块时,调用注册函数将模块A中声明的回调函数CF_XXX的地址传给pfn,即pfn=CF_XXX;(函数名称CF_XXX其实是个指针,指向回调函数的地址) 。

 

 2、举例

回调函数的yi个应用场景:网络编程。 在网络编程中,为了体现模块化,一般把通讯和数据处理划分开来,即通讯模块负责协议定义、数据收发,而数据处理模块只负责对收发的数据进行解析和打包,假如通讯模块开启了一个线程在持续地接收数据,这个时候问题来了,它通过什么手段把数据交到数据处理模块手中呢?每次收到数据,拿到数据处理模块的指针完成相关操作,这样有犯了两个类指针互相指的错误,也破坏了两个模块的独立性。使用回调函数这些问题都迎刃而解了,下面给出部分伪代码:

通讯模块

typedef void (*DataReceiveCBFunc)(ReceiveParam & recvParam);  // 回调函数原型定义

 

// 开始接收,数据处理模块调用,相对于注册回调函数

static BOOL StartReceive(DataReceiveCBFunc pfnData, LPVOID lpContext,……);

// 接收数据的线程,一收到数据就通知回调

static UINT TH_Receive(LPVOID lp);

 

数据处理模块

// 开始接收数据,开启监听线程,调用上面的StartReceive函数

int StartReceiveInfo(int nListenPort, std::string strLocalIP);

// 数据接收回调函数,被CUdpEx::TH_Receive()回调

static void RecvInfoCallback(ReceiveParam &recvParam);  

 

3、关于常见的几个函数构成的回调函数

本小节的原文地址:https://blog.csdn.net/biubiuibiu/article/details/56286725 
 

下面来说说回调函数的几个要点:

[ 被调用的函数A ]    可以认为是最后核心的被执行的函数;这个就是回调函数。

[ 对被调用函数进行调用的函数B ]   可以认为是绑定这个被调函数A的地方,让它以一种什么样的形式来使用(例如在循环体中执行N次,对别的变量赋值等等);

[ 触发主动调用函数的函数C ]   真正开始触发各个函数被调用的地方。

在上面的这三个函数A、B、C中,函数A和C通常是在一个应用层级来写的,而函数B则可能在较低的层级实现。

 

第一块所实现的一些应用逻辑的功能函数,就是函数A或者函数C,具体看是哪一个被传入函数B的,哪一个是主动调B的,被当做参数传入给B的,就是回调函数A,主动调B的,是真正触发各个函数被调用的函数C。

#include 
#include 
 
//简单点,让我们命名的方式简单点
/* 定义一种输出为int型,输入参数为两个int型的这一类的函数,并给它一个统一的类别名字,callBackfunName*/
typedef int(*funName)(int x1, int x2);
 
 
/* 下述 add() 和 mix() 是两个符合funName这种形式的函数,通常它们处在应用层的下一层,即库函数或者外部接口等*/
int add(int x, int y)          //函数A,回调函数
{
    printf("add() is called.\n");
    return (x+y);
}
 
int mix(int x, int y)       
{
    printf("mix() is called.\n");
    return (x*y);
}
 
 
void call_by_funName(funName f,int x)//函数B,调用调用函数A的函数  callBackfunName此时就被当做int char等一样的形式来用!
{
    int ret = -100;
    printf("call_by_funName is begain.\n");
    ret = f(x,x);
    printf("call_by_funName is finished.\n");
    printf("[ %d ]\n",ret);
}
 
int main()//函数C,调用B的函数,首先引起各个调用的地方
{
    callBackfunName f1 = mix;
    callBackfunName f2 = add;
    call_by_funName(f1,10);
    call_by_funName(f2,20);
    system("pause");
    return 0;
}

 

四、回调函数的通俗解释:

        本解释的原文地址:https://blog.csdn.net/bujiongdan/article/details/80675358
        你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。

 
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值