不知道你们有没有试过把C++类里的函数作为回调函数,有时候C++可能有这样的需求,但是C++类里的函数作为回调不能像C的函数那样直接回调(毕竟C++要对象;C和我一样,没对象,用struct做的假对象不算)。这里说一下怎么处理这种问题。
最挫的办法
把回调函数套一个娃
#include <iostream>
using namespace std;
class Test
{
public:
void func(int data)
{
cout << "data = " << data << endl;
}
};
// 这个就是给func套娃的函数
void shell_func(Test *object, int data)
{
object->func(data);
}
void run_callback(void (*callback) (Test *, int), Test *object, int data)
{
callback(object, data);
}
int main()
{
Test test;
run_callback(shell_func, &test, 1234);
return 0;
}
如此这般,main里就可以通过回调的方式调用到test对象里的func函数了。通过shell_func对Test里的函数封装一把,这样就和回调C的函数一样了。但是太挫了。
逼格高一点的方法
#include <iostream>
using namespace std;
class Test
{
public:
void func(int data)
{
cout << "data = " << data << endl;
}
};
void run_callback(void (*callback) (void *, int), void *object, int data)
{
callback(object, data);
}
int main()
{
Test test;
run_callback((void (*) (void *, int)) &Test::func, &test, 1234);
return 0;
}
和最挫的办法类似,还是需要在callback的时候传入对象。其实类似python,把对象作为类函数(或许我应该叫这个函数为方法)的第一个参数,C++也可以像python这样玩。
这里也就是把Test::func由void (Test::*) (int)
类型强制转换为void (*) (void *, int)
类型,这样一来,回调函数的第一个参数就可以传对象了。
逼格高一点的同时可读性好一点的方法
#include <iostream>
using namespace std;
class Test
{
public:
void func(int data)
{
cout << "data = " << data << endl;
}
};
typedef void (*FUNC) (void *, int);
void run_callback(FUNC callback, void *object, int data)
{
callback(object, data);
}
int main()
{
Test test;
run_callback((FUNC) &Test::func, &test, 1234);
return 0;
}
因为逼格高一点的方法里,run_callback和强制转换func的类型时,写得不够优雅,所以可以搞一个typedef,把void (*) (void *, int)
类型起一个别名FUNC
,这样run_callback和强制类型转换时看起来就简单多了。
回调类函数有什么用
还是有点用的,可以写一些策略模式。比如(编译下面代码需要打开c++11选项):
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Test
{
public:
static int count;
int index;
Test()
{
index = ++count;
}
void func1(int data)
{
cout << "in test"<< index <<".func1 data = " << data << endl;
}
void func2(int data)
{
cout << "in test"<< index <<".func2 data = " << data << endl;
}
void func3(int data)
{
cout << "in test"<< index <<".func3 data = " << data << endl;
}
};
int Test::count = 0;
typedef void (*FUNC) (void *, int);
map<string, FUNC> callback_map = {
{"func1", (FUNC) &Test::func1},
{"func2", (FUNC) &Test::func2},
{"func3", (FUNC) &Test::func3}
};
int main()
{
Test test1;
Test test2;
int index;
string operation;
int data;
cin >> index >> operation >> data;
Test *test = &test1;
switch (index) {
case 1:
test = &test1;
break;
case 2:
test = &test2;
break;
}
callback_map[operation](test, data);
return 0;
}
如果你不知道怎么打开c++11,那也不纠结了,直接用命令行这样编译(假设你把代码命名为callback_class_func.cpp):
g++ callback_class_func.cpp -o callback_class_func -std=c++11
可以在代码里减少很多if else。
这个代码类似于一些根据用户输入或者网络交互的时候,传入是字符串,但是这个字符串就是函数命。这种时候如果情况特别多,那if可以写死人。但是用一个map映射到回调函数里,就会方便很多。,map映射,只要保证这些回调函数的形参是一样的,就可以批量处理了。