c++回撥機制全解:定義原型,註冊,回撥,封裝.
阿新 • • 發佈:2019-02-05
模組A呼叫模組B,但在B中,需要反過來呼叫到A的函式a(),則a()稱為回撥函式,在B中需要做的事:1.約定回撥函式原型.2.定義註冊回撥函式在A中需要:1.定義回撥函式2.呼叫B的註冊回撥函式使用回撥函式的幾個步驟:1.在B中,約定藉口規範,定義回撥函式a()的原型這裡回撥函式原型的定義最好遵循typedef void (*SCT_XXX)(LPVOID lp, const CBParamStruct& cbNode); SCT_XXX -回撥函式名稱lp -回撥上下文CBParamStruct -回撥引數,一般由於要回調的引數不止一個,所以定義一個結構體比較方便。
2.在B中,定義註冊回撥函式void RCF_XXX(SCT_XXX pfn, LPVOID lp);
RCF_XXX -註冊函式名pfn -回撥函式名稱(是指標)lp -是回撥上下文. 一般在A模組初始化完B模組後呼叫,將A模組中定義的回撥函式地址賦值給pfn,lp賦值為this。
3.在A中,定義回撥函式回撥函式宣告成靜態的,static void CF_XXX(LPVOID lp, const CBParamStruct& cbNode); 函式的引數必須與B模組中回撥函式原型的引數保持一致。在A中初始化B模組時,呼叫B的註冊函式將模組A中宣告的回撥函式CF_XXX的地址傳給pfn,即pfn=CF_XXX;(函式名稱CF_XXX其實是個指標,指向回撥函式的地址) 。然後lp一般為this.但若作為類,C++的類成員函式不能像普通函式那樣用於回撥,因為每個成員函式都需要有一個物件例項去呼叫它。通常情況下,要實現成員函式作為回撥函式,常用的方法就是把該成員函式設計為靜態成員函式,但這樣做有一個缺點,就是會破壞類的結構性,因為靜態成員函式只能訪問該類的靜態成員變數和靜態成員函式,不能訪問非靜態的,要解決這個問題,需要把物件例項的指標或引用做為引數傳給它。利用回撥代理類,可以簡單的實現非靜態函式的回撥。程式碼:
2.在B中,定義註冊回撥函式void RCF_XXX(SCT_XXX pfn, LPVOID lp);
RCF_XXX -註冊函式名pfn -回撥函式名稱(是指標)lp -是回撥上下文. 一般在A模組初始化完B模組後呼叫,將A模組中定義的回撥函式地址賦值給pfn,lp賦值為this。
3.在A中,定義回撥函式回撥函式宣告成靜態的,static void CF_XXX(LPVOID lp, const CBParamStruct& cbNode); 函式的引數必須與B模組中回撥函式原型的引數保持一致。在A中初始化B模組時,呼叫B的註冊函式將模組A中宣告的回撥函式CF_XXX的地址傳給pfn,即pfn=CF_XXX;(函式名稱CF_XXX其實是個指標,指向回撥函式的地址) 。然後lp一般為this.但若作為類,C++的類成員函式不能像普通函式那樣用於回撥,因為每個成員函式都需要有一個物件例項去呼叫它。通常情況下,要實現成員函式作為回撥函式,常用的方法就是把該成員函式設計為靜態成員函式,但這樣做有一個缺點,就是會破壞類的結構性,因為靜態成員函式只能訪問該類的靜態成員變數和靜態成員函式,不能訪問非靜態的,要解決這個問題,需要把物件例項的指標或引用做為引數傳給它。利用回撥代理類,可以簡單的實現非靜態函式的回撥。程式碼:
#ifndef CCALLBACKPROXY_H #define CCALLBACKPROXY_H template<typename Tobject, typename Tparam> class CCallbackProxy { //約定回撥函式原型 typedef void (Tobject::*CbFun)(Tparam*); public: //此處相當於註冊函式 void Set(Tobject *pInstance, CbFun pFun); bool Exec(Tparam* pParam); private: CbFun pCbFun; //回撥函式指標 Tobject* m_pInstance; //呼叫物件 }; #if 1 //設定呼叫物件及其回撥函式 template<typename Tobject, typename Tparam> void CCallbackProxy<Tobject, Tparam>::Set(Tobject *pInstance , CbFun pFun) { m_pInstance = pInstance; pCbFun = pFun; } //呼叫回撥函式 template<typename Tobject, typename Tparam> bool CCallbackProxy<Tobject, Tparam>::Exec(Tparam* pParam) { (m_pInstance->*pCbFun)(pParam); return true; } #endif #endif // CCALLBACKPROXY_H ///non cpp file ///main.cpp #include <QCoreApplication> #include "ccallbackproxy.h" class CTest { public: CTest(int nNum) { m_nSum = nNum; } void CbPrintSum(int *pnAddNum) { printf("The Sum is %d\n", m_nSum+*pnAddNum); } private: int m_nSum; }; int main(int argc, char* argv[]) { CCallbackProxy<CTest, int> CbProxy; CTest TestInstance(20); //註冊 CbProxy.Set(&TestInstance, &CTest::CbPrintSum); int nNum = 1000; CbProxy.Exec(&nNum); return 0; }