CPP实现回调函数
得到函数的地址是其中一个关键步骤。
普通和函数和类的静态成员函数都分配有确定的函数地址,但是类的普通函数是类共用的,并不会给类的每一个实例都分配一个独立的成员函数,这样就太浪费存储资源了。所以类的非静态函数作为回调函数是有区别的
普通函数作为回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <iostream>
void programA_FunA1() { printf("I'am ProgramA_FunA1 and be called..\n"); }
void programA_FunA2() { printf("I'am ProgramA_FunA2 and be called..\n"); }
void programB_FunB1(void (*callback)()) { printf("I'am programB_FunB1 and be called..\n"); callback(); }
int main(int argc, char **argv) { programA_FunA1();
programB_FunB1(programA_FunA2); }
|
类的静态函数作为回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <iostream>
class ProgramA { public: void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); }
static void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); } };
class ProgramB { public: void FunB1(void (*callback)()) { printf("I'am ProgramB.FunB1() and be called..\n"); callback(); } };
int main(int argc, char **argv) { ProgramA PA; PA.FunA1();
ProgramB PB; PB.FunB1(ProgramA::FunA2); }
|
可以看出,以上两种方式没有什么本质的区别。
但这种实现有一个很明显的缺点:static 函数不能访问非static 成员变量或函数,会严重限制回调函数可以实现的功能。
类的非静态函数作为回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <iostream>
class ProgramA { public: void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); }
void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); } };
class ProgramB { public: void FunB1(void (ProgramA::*callback)(), void *context) { printf("I'am ProgramB.FunB1() and be called..\n"); ((ProgramA *)context->*callback)(); } };
int main(int argc, char **argv) { ProgramA PA; PA.FunA1();
ProgramB PB; PB.FunB1(&ProgramA::FunA2, &PA); }
|
这种方法可以得到预期的结果,看似完美,但是也存在明显不足。
比如在programB中FunB1还使用 programA的类型,也就我预先还要知道回调函数所属的类定义,当programB想独立封装时就不好用了。
std::funtion和std::bind的使用
C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <iostream>
#include <functional>
class ProgramA { public: void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); }
void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); }
static void FunA3() { printf("I'am ProgramA.FunA3() and be called..\n"); } };
class ProgramB { typedef std::function<void ()> CallbackFun; public: void FunB1(CallbackFun callback) { printf("I'am ProgramB.FunB2() and be called..\n"); callback(); } };
void normFun() { printf("I'am normFun() and be called..\n"); }
int main(int argc, char **argv) { ProgramA PA; PA.FunA1();
printf("\n"); ProgramB PB; PB.FunB1(normFun); printf("\n"); PB.FunB1(ProgramA::FunA3); printf("\n"); PB.FunB1(std::bind(&ProgramA::FunA2, &PA)); }
|
std::funtion支持直接传入函数地址,或者通过std::bind指定。
简而言之,std::funtion是定义函数类型(输入、输出),std::bind是绑定特定的函数(具体的要调用的函数)。