目标读者:能够理解回调函数的含义
把类的成员函数作为回调函数有三个步骤:
- 实现这个成员函数,
- 对这个函数进行绑定,
- 将绑定好的函数指针传给调用函数。
一、添加头文件
#include <functional>
二、typedef一个函数指针类型
这一步是为了方便地得到所需的函数指针变量。
typedef std::function<void (int,int)> Fun;//注意void与()之间是空格而不是‘,’
typedef std::function<返回类型 (参数一,参数二)> 函数指针类型名称
三、函数绑定
要想直接将一个类成员函数设置为一个回调函数,而不是使用静态成员函数,需要用到std::bind。
Fun fun = bind(&Test::callback, this,placeholders::_1,placeholders::_2);
回调函数指针类型 函数指针变量 = bind(&类::回调函数, 类指针,参数占位符);
》关于placeholders
placeholders域在这里起到占位符的作用,指明该参数是调用者在使用回调函数时传入的第几个参数。例如placeholders域下的
_1
、`_2分别代表调用者传入的第一个、第二个参数。举个例子:
读者可以先看完下面回调函数的代码实现后再回过来看这个例子,方便理解。
callback
是一个有两个参数的回调函数。实现一个作差的功能。void Test::callback(int a,int b) { printf("%d - %d = %d", a, b, a - b); }
绑定时,设置把传入的第2个参数传给变量a,把传入的第1个参数传给变量b。
Fun fun = bind(&Test::callback,this,placeholders::_2,placeholders::_1);
调用者在实际调用时,把值2传给变量a,把值1传给变量b。
fun(1,2);//fun(placeholder::_1, placeholder::_2);
计算结果:
2 - 1 = 1
绑定时不仅可以传入占位符,还可以直接传入变量。例如
int x = 5; Fun fun = bind(&Test::callback,this,placeholders::_2,x);
fun(1,2);
输出:
2 - 5 = -3
四、代码实例
在这个代码实例中,回调函数,绑定函数和调用函数都放在一个类里面,在实际项目中绑定函数和回调函数一般处在一个类中,而调用函数则存在于其他的类中。
#include <stdio.h>
#include <functional>
using namespace std;
class Test
{
public:
typedef std::function<void (int,int)> Fun;//typedef一个函数指针
void callback(int a,int b)/*回调函数*/
{
printf("%d+%d = %d",a,b,a+b);
}
void bind()/*绑定*/
{
Fun fun = bind(&Test::callback, this,placeholders::_1,placeholders::_2);
call(1, fun);
}
void call(int a,Fun f)/*调用者*/
{
f(a,2);
}
};
int main()
{
Test test;
test.bind();
return 0;
}
输出结果:
1+2=3