引言
之前在项目中使用winpcap遇到过回调函数,但当时是使用非回调方法实现的数据捕获,并未深究回调方法,如今项目中又遇到,特回来填坑。。
定义
回调,说白了就是函数指针的一种用法。
1.函数指针
函数指针是指向函数的指针变量。函数的类型由它的返回类型和形参类型共同决定,与函数名无关。例如:
bool lengthCompare(const string &, const string &);
该函数的类型是bool (const string &, const string &)
想要声明一个可以指向该函数的指针,只需用指针替换函数名即可:
bool (*pf)(const string &, const string &)//*pf两端的括号不可少
pf=lengthCompare; //等价于pf=&lengthCompare;&符号可选
bool b1=pf("hello", "goodbye"); //调用lengthCompare函数
bool b2=(*pf)("hello", "goodbye"); //一个等价的调用
bool b3=lengthCompare("hello", "goodbye"); //另一个等价的调用
C++在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,就可以用该指针变量调用函数了。
2.typedef函数指针
往往利用typedef来简化使用函数指针时的声明和定义操作。
型式:typedef 返回类型(*新类型)(参数表)
typedef bool (*pfType)(const string &, const string &); //定义新的函数指针类型
pfType pf; //使用新函数指针类型定义了变量pf
bool lengthCompare(const string &a, const string &b) //函数实现
{
/*do something*/
}
void main()
{
pf = lengthCompare;
bool b2 = (*pf)("hello", "goodbye");
}
3.回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数a的指针(地址)作为参数传递给另一个函数b,当这个指针被用来调用其所指向的函数a时,我们就说函数a是回调函数。回调函数不是由该函数的实现方(模块A)直接调用,而是在特定的事件或条件发生时由另外的一方(模块B)调用的,用于对该事件或条件进行响应。
即:模块A要通过模块B的某个(接口)函数b()完成一定的功能,但是函数b()自己无法实现全部功能,需要反过头来调用模块A中的某个函数a()来完成,这个a()就是回调函数。
使用步骤
1. 定义一个回调函数;
包括定义回调函数a()的函数原型(声明),也就是约定模块B中的接口规范;实现具体回调函数a()。
2. 提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;
包括函数b()的声明和实现。
3. 当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。
运行时,函数b()中调用具体的函数a()
例子
#include <iostream>
using namespace std;
typedef int (*FP_CALC)(int,int); //步骤1.1:定义一个函数指针类型,即定义回调函数a()的函数原型
//步骤1.2:实现各种回调函数,函数的参数必须与回调函数原型的参数保持一致
int myadd(int a, int b)
{
return a + b;
}
int mysub(int a, int b)
{
return a - b;
}
int mymul(int a, int b)
{
return a * b;
}
int mydiv(int a, int b)
{
return b? a/b : -1;
}
//被调函数
int GetCallBack(FP_CALC callback, int a, int b) //步骤2:将回调函数的函数指针注册给调用者
{
return callback(a,b);
}
int main()
{
double a=100,b=20;
cout<<"a+b="<<GetCallBack(myadd, a, b)<<endl;//步骤3:调用具体的回调函数
cout<<"a-b="<<GetCallBack(mysub, a, b)<<endl;//依据不同条件调用不同的回调函数
cout<<"a*b="<<GetCallBack(mymul, a, b)<<endl;
cout<<"a/b="<<GetCallBack(mydiv, a, b)<<endl;
return 0;
}
输出
a+b=120
a-b=80
a*b=2000
a/b=5
注意
- 回调函数可以象普通函数一样被程序调用,但是只有它被当作参数传递给被调函数时才能称作回调函数。
- 如果赋了不同的值给该参数,那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。