1.普通函数作为回调函数
#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);
}
2 .类的静态函数作为回调函数
#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 成员变量或函数,会严重限制回调函数可以实现的功能。
3. 类的非静态函数作为回调函数
#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想独立封装时就不好用了。
这里还有一种方法可以避免这样的问题,可以把非static的回调函数 包装为另一个static函数,这种方式也是一种应用比较广的方法。
#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"); }static void FunA2Wrapper(void *context) {printf("I'am ProgramA.FunA2Wrapper() and be called..\n");((ProgramA *)context)->FunA2(); // 此处调用的FunA2()是context的函数, 不是this->FunA2()}
};class ProgramB {public:void FunB1(void (ProgramA::*callback)(), void *context) {printf("I'am ProgramB.FunB1() and be called..\n");((ProgramA *)context->*callback)();}void FunB2(void (*callback)(void *), void *context) {printf("I'am ProgramB.FunB2() and be called..\n");callback(context);}
};int main(int argc, char **argv) {ProgramA PA;PA.FunA1();ProgramB PB;PB.FunB1(&ProgramA::FunA2, &PA); // 此处都要加&printf("\n");PB.FunB2(ProgramA::FunA2Wrapper, &PA);
}
这种方法相对于上一种,ProgramB中没有ProgramA的任何信息了,是一种更独立的实现方式。
FunB2()通过调用FunA2Wrapper(),实现间接的对FunA2()的调用。FunA2()可以访问和调用对类内的任何函数和变量。多了一个wrapper函数,也多了一些灵活性。
上面借助wrapper函数实现回调,虽然很灵活,但是还是不够优秀,比如:
1)多了一个不是太有实际用处的wrapper函数。
2)wrapper中还要对传入的指针进行强制转换。
3)FunB2调用时,不但要指定wrapper函数的地址,还要传入PA的地址。
还有更灵活、直接的方式。
std::funtion和std::bind可以登场了。
std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda表达式、函数指针、以及其它函数对象等[1]。
std::bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的[2]。
#include <iostream>#include <functional> // fucntion/bindclass 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是绑定特定的函数(具体的要调用的函数)。
相比于wrapper方法,这个方式要更直接、简洁很多。