一直以来都被回调函数的定义给整蒙了。最近又仔细学了会,感觉回调函数,我认为就是将一个函数指针A作为参数传入另外一个函数B,然后在函数B中调用函数A。
普通回调
具体先看一个简单的例子:
- #include<stdio.h>
- void printWelcome(int len)
- {
- printf("welcome -- %d\n", len);
- }
- void printGoodbye(int len)
- {
- printf("byebye-- %d\n", len);
- }
- void callback(int times, void (* print)(int))
- {
- int i;
- for (i = 0; i < times; ++i)
- {
- print(i);
- }
- printf("\n welcome or byebye !\n");
- }
- void main(void)
- {
- callback(10, printWelcome);
- callback(10, printGoodbye);
- }
当然,这只是一个很简单的例子。在各种c++中,回调可是牛逼闪闪。
在c++中,一般需要使用类进行函数的封装。但是在调用一般的类的成员函数时,使用类的成员调用时,需要传递this指针
《深入探索C++对象模型》中提到成员函数时,当成员函数不是静态的,虚函数,那么我们有以下结论:
(1) &类名::函数名 获取的是成员函数的实际地址;
(2) 对于函数x来讲obj.x()编译器转化后表现为x(&obj),&obj作为this指针传入;
(3) 无法通过强制类型转换在类成员函数指针与其外形几乎一样的普通函数指针之间进行有效的转换。
所以,要在回调函数中传入一个类的普通成员函数时,this指针无处安放,使得回调函数比较复杂。
类成员函数回调
在c++中,常用的回调函数场景是,在一个类A中,有一个普通成员函数a,在类B中,有一个普通成员函数b,在b中,想要回调函数a,这才是c++回调函数的正确打开方式。
先上一段代码:
- #include <iostream>
- #include <functional>
- using namespace std;
- using namespace std::placeholders;
- typedef std::function<void(int,int)> Fun;
- class B{
- public:
- void call(int a,Fun f)
- {
- f(a,2);
- }
- };
- class Test{
- public:
- void callback(int a,int b)
- {
- cout<<a<<"+"<<b<<"="<<a+b<<endl;
- }
- void bind()
- {
- Fun fun=std::bind(&Test::callback,this,_1,_2);
- B b;
- b.call(1,fun);
- }
- };
- int main()
- {
- Test test;
- test.bind();
- return 0;
- }
在分析上面程序之前,先介绍一下两个辅助函数,分别是bind函数和function函数,这两个函数之前是boost函数成员,现在加入到c++11标准中,使用更加方便。
bind函数
定义在头文件functional中。可以看成是对一个函数的改造器,可以借助于集合的观点来说(尽管可能没这回事),可以将bind函数看作是返回一个子函数。这个子函数可以是bind绑定的函数的子集,也可以是本身。
一般常用语法是: newFunName=bind(oldFunName,arg_list);
bind函数返回一个新的函数对象。其中bind第一个参数是oldFunName,它是待绑定的函数名,arg_list是oldFunName的参数列表。注意,这个参数列表是旧函数的参数列表,前面提到,返回的是子函数。我们可以随便给子函数定几个参数,但是肯定不能多于bind所绑定的原函数的参数个数。举个例子:
- //g是一个有两个参数的可调用对象
- auto g=bind(f,a,b,_2,c,_1);
- //其中f是具有5个参数的函数
- //当我们调用g(x,y)时,实际调用的是f(a,b,y,c,x)
上面出现的_1,_2是它的占位符,bind最多可以使用9个占位符。这个占位符命名在std的placeholders中,使用时,要使用using std::placeholders.
function函数
function是一个函数对象的“容器”。
如function<int(int,int)> fun; fun是一个函数模板,可以接受两个int型参数,并返回一个int型参数。平时可以将它赋值给一个函数指针。
例如上面的回调函数:
- Fun fun=std::bind(&Test::callback,this,_1,_2);
关于bind和function函数,再举一个例子,这个例子摘自
这里。
- #include <iostream>
- #include <functional>
- using namespace std;
- typedef std::function<void ()> fp;
- void g_fun()
- {
- cout<<"g_fun()"<<endl;
- }
- class A
- {
- public:
- static void A_fun_static()
- {
- cout<<"A_fun_static()"<<endl;
- }
- void A_fun()
- {
- cout<<"A_fun()"<<endl;
- }
- void A_fun_int(int i)
- {
- cout<<"A_fun_int() "<<i<<endl;
- }
- //非静态类成员,因为含有this指针,所以需要使用bind
- void init()
- {
- fp fp1=std::bind(&A::A_fun,this);
- fp1();
- }
- void init2()
- {
- typedef std::function<void (int)> fpi;
- //对于参数要使用占位符 std::placeholders::_1
- fpi f=std::bind(&A::A_fun_int,this,std::placeholders::_1);
- f(5);
- }
- };
- int main()
- {
- //绑定到全局函数
- fp f2=fp(&g_fun);
- f2();
- //绑定到类静态成员函数
- fp f1=fp(&A::A_fun_static);
- f1();
- A().init();
- A().init2();
- return 0;
- }
- 转载地址:https://blog.csdn.net/hyp1977/article/details/51784520