“我所说的一切,无非是提醒后到达这个路口的人,你绝不是只有一条路,而是四通八达的,你可以做出选择。 ”
回调函数
回调函数是一个很有意思的功能,也解决了一些很棘手的问题。什么是回调函数呢,在C++里面,一般是有一个A类对象a,一个B类对象b,对象b要调用a中的某个函数afunc,同时需要a在执行这个函数时,在某个地方调用b中的函数bfunc。回调,回去调用的意思。
知乎上有个关于如何理解回调函数的例子:
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。 作者:常溪玲链接:https://www.zhihu.com/question/19801131/answer/13005983来源:知乎
但是我觉得这个表述会令人误解。实际上,电话号码并不是回调函数,你去书店取货才是一个回调函数,电话号码只是相当于回调函数的指针,有了这个指针之后,店员就可以通过这个指针调用“让你去取货”这一回调函数。在这里,店员相当于A类对象a,买东西的你相当于B类对象b。所以在整个过程中,你首先需要给店员一个指针,告诉他怎么才能让你去取货,然后店员接收这个指针之后(记下电话号码),就知道怎么让你去取货了。
所以回调函数简单来说就是给别人一个函数指针,让别人来调用我。
类成员函数作为回调函数
如上文所述,b给a一个指针,让a来调用自己的某个函数,因为b是一个类对象,普通成员函数无法直接作为指针给a,因为成员函数的定义是所有B类对象共有的,直接传递给a调用的时候a无法定位是哪一个对象,所以函数里面用到的数据也无法定位。而为什么我们在一个类里面可以直接调用类中别的函数呢,那是因为编译器会隐式传入this指针的值,也就是说,加入你在类的成员函数bfun1() 里面调用 bfunc2()
1
bfunc2(x)
实际上你调用的是
1
bfunc2(this, x)
怎么办呢,C++里面提供了一个bind函数解决了这个问题,bind函数提供了绑定加改造函数的功能,改造什么呢,改造函数的参数。它可以把一个接收两个参数的函数改造成接收一个参数的函数,另一个参数在改造时确定。
比如以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
using namespace std::placeholders; //占位符_1的namespace
typedef function<void(int)> funcInt;
class B{
public:
void PrintTwoInt(int x, int y);
void bfunc(){
funcInt printOneInt = bind(&B::PrintTwoInt, this, 0, _1);
printOneInt(1);
}
};
bfunc()函数里面把PrintTwoInt改造成了只接收一个参数y的函数,x形参确定为 0 ,也把成员函数的隐式参数也确定了,设定为当前这个对象的this指针。这样一个绑定后的函数——printOneInt就可以直接调用,或者也可以作为回调函数的指针给别人调用了。
当然也可以给两个形参都指定默认值,比如
1
2
funcInt printOneInt = bind(&B::PrintTwoInt, this, 0, 0);
printOneInt(1);
那么实际调用时传入的参数1就完全不起作用了,函数还是会输出两个0。
—— Chen