CPP实现回调函数
得到函数的地址是其中一个关键步骤。
普通和函数和类的静态成员函数都分配有确定的函数地址,但是类的普通函数是类共用的,并不会给类的每一个实例都分配一个独立的成员函数,这样就太浪费存储资源了。所以类的非静态函数作为回调函数是有区别的
普通函数作为回调函数
| 12
 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);
 }
 
 | 
类的静态函数作为回调函数
| 12
 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 成员变量或函数,会严重限制回调函数可以实现的功能。
类的非静态函数作为回调函数
| 12
 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++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成
| 12
 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是绑定特定的函数(具体的要调用的函数)。