C++回調函數學習
- 遇到問題,要學習C++回調函數
遇到問題,要學習C++回調函數
來吧,直接看代碼吧
共有4種方法,每種方法都有標識,對用的屏蔽和打開就可以使用
原文在這里:
#include<iostream>
#include<functional>//*2.1 普通函數作為回調函數*//
//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.2 類的靜態函數作為回調函數*//
//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:
// static void FunB1(void(callback)())
// {
// printf("I'am ProgramB_FunB1 and be called..\n");
// callback();
// }
//};
//
//int main()
//{
// ProgramA Pa;
// Pa.FunA1();
//
// ProgramB Pb;
// Pb.FunB1(ProgramA::FunA2);
//}//****可以看出,以上兩種方式沒有什么本質的區別。
//****但這種實現有一個很明顯的缺點:static 函數
//****不能訪問非static 成員變量或函數,會嚴重限制回調函數可以實現的功能。***2.3 類的非靜態函數作為回調函數*//
//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()
//{
// ProgramA Pa;
// Pa.FunA1();
//
// ProgramB Pb;
// Pb.FunB1(&ProgramA::FunA2,&Pa);
//}
/******這種方法可以得到預期的結果,看似完美,但是也存在明顯不足。
*******比如在programB中FunB1還使用 programA的類型,也就我預先還要知道
*******回調函數所屬的類定義,當programB想獨立封裝時就不好用了。*///*2.4 這里還有一種方法可以避免這樣的問題,可以把非static的回調函數 包裝為另一個static函數,這種方式也是一種應用比較廣的方法*//
//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()
//{
// ProgramA Pa;
// Pa.FunA1();
//
// ProgramB Pb;
// Pb.FunB1(&ProgramA::FunA2,&Pa);
//
// std:: cout<< "\n" ;
// Pb.FunB2(ProgramA::FunA2Wrapper,&Pa);
//}
//
這種方法相對于上一種,ProgramB中沒有ProgramA的任何信息了,是一種更獨立的實現方式。
FunB2()通過調用FunA2Wrapper(),實現間接的對FunA2()的調用。FunA2()可以訪問和調用對類內的任何函數和變量。
多了一個wrapper函數,也多了一些靈活性。
?
上面借助wrapper函數實現回調,雖然很靈活,但是還是不夠優秀,比如:
1)多了一個不是太有實際用處的wrapper函數。
2)wrapper中還要對傳入的指針進行強制轉換。
3)FunB2調用時,不但要指定wrapper函數的地址,還要傳入PA的地址。//*3 std::funtion和std::bind的使用*//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()
{ProgramA Pa;Pa.FunA1();printf("\n");ProgramB Pb;Pb.FunB1(normFun);std::cout << "\n";Pb.FunB1(ProgramA::FunA3);printf("\n");Pb.FunB1(std::bind(&ProgramA::FunA2,&Pa));
}
//*****std::funtion支持直接傳入函數地址,或者通過std::bind指定。
//*****簡而言之,std::funtion是定義函數類型(輸入、輸出),std::bind是綁定特定的函數(具體的要調用的函數)。