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方法,這個方式要更直接、簡潔很多。