C++ 实现把非静态成员函数作为回调函数(非static)

来源:互联网 发布:知乎排名 编辑:程序博客网 时间:2024/05/11 14:05

众所周知,C++的类成员函数不能像普通函数那样用于回调,因为每个成员函数都需要有一个对象实例去调用它。

        通常情况下,要实现成员函数作为回调函数,一种常用的方法就是把该成员函数设计为静态成员函数,但这样做有一个缺点,就是会破坏类的结构性,因为静态成员函数只能访问该类的静态成员变量和静态成员函数,不能访问非静态的,要解决这个问题,需要把对象实例的指针或引用做为参数传给它。

        在一次偶然的机会下,看到了一种方法可以简单的实现回调非静态成员函数,其原理就是把要调用该成员函数的对象实例赋值给一个变量,然后通过该变量来调用成员函数。把逻辑整理了一下,然后写了一个简单的回调代理类,通过这个类,可以简单的实现非静态函数的回调。


CallbackProxy.h

[cpp] view plaincopy
  1. #ifndef __CALLBACK_PROXY_H__  
  2. #define __CALLBACK_PROXY_H__  
  3.   
  4. //Tobject:调用对象的类型,Tparam回调函数参数的类型  
  5. template<typename Tobject, typename Tparam>  
  6. class CCallbackProxy  
  7. {  
  8.     typedef void (Tobject::*CbFun)(Tparam*);  
  9.   
  10. public:  
  11.     void Set(Tobject *pInstance, CbFun pFun);  
  12.     bool Exec(Tparam* pParam);  
  13.   
  14. private:      
  15.     CbFun       pCbFun;     //回调函数指针  
  16.     Tobject*    m_pInstance;    //调用对象  
  17. };  
  18.   
  19. //设置调用对象及其回调函数  
  20. template<typename Tobject, typename Tparam>  
  21. void CCallbackProxy<Tobject, Tparam>::Set(Tobject *pInstance , CbFun pFun)  
  22. {  
  23.     m_pInstance = pInstance;   
  24.     pCbFun = pFun;  
  25. };  
  26.   
  27. //调用回调函数  
  28. template<typename Tobject, typename Tparam>  
  29. bool CCallbackProxy<Tobject, Tparam>::Exec(Tparam* pParam)  
  30. {  
  31.     (m_pInstance->*pCbFun)(pParam);  
  32.     return true;  
  33. }  
  34.   
  35. #endif  


下面演示下如何使用该类

test.cpp
[cpp] view plaincopy
  1. #include "CallbackProxy.h"  
  2.   
  3. class CTest  
  4. {  
  5. public:  
  6.     CTest(int nNum);  
  7.     void CbPrintSum(int *pnAddNum){printf("The Sum is %d\n", m_nSum+*pnAddNum);};  
  8.   
  9. private:  
  10.     int m_nSum;  
  11. };  
  12.   
  13. int main(int argc,  char* argv[])  
  14. {  
  15.     CCallbackProxy<CTest, int> CbProxy;  
  16.   
  17.     CTest TestInstance(20);  
  18.   
  19.     CbProxy.Set(&TestInstance, &CTest::CbPrintSum);  
  20.   
  21.     int nNum = 1000;  
  22.     CbProxy.Exec(&nNum);  
  23.   
  24.     return 0;  
  25. }  
  26.   
  27. CTest::CTest(int nNum):  
  28. m_nSum(nNum)  
  29. {  
  30.   
  31. }  

    众所周知,C++的类成员函数不能像普通函数那样用于回调,因为每个成员函数都需要有一个对象实例去调用它。

            通常情况下,要实现成员函数作为回调函数,一种常用的方法就是把该成员函数设计为静态成员函数,但这样做有一个缺点,就是会破坏类的结构性,因为静态成员函数只能访问该类的静态成员变量和静态成员函数,不能访问非静态的,要解决这个问题,需要把对象实例的指针或引用做为参数传给它。

            在一次偶然的机会下,看到了一种方法可以简单的实现回调非静态成员函数,其原理就是把要调用该成员函数的对象实例赋值给一个变量,然后通过该变量来调用成员函数。把逻辑整理了一下,然后写了一个简单的回调代理类,通过这个类,可以简单的实现非静态函数的回调。


    CallbackProxy.h

    [cpp] view plaincopy
    1. #ifndef __CALLBACK_PROXY_H__  
    2. #define __CALLBACK_PROXY_H__  
    3.   
    4. //Tobject:调用对象的类型,Tparam回调函数参数的类型  
    5. template<typename Tobject, typename Tparam>  
    6. class CCallbackProxy  
    7. {  
    8.     typedef void (Tobject::*CbFun)(Tparam*);  
    9.   
    10. public:  
    11.     void Set(Tobject *pInstance, CbFun pFun);  
    12.     bool Exec(Tparam* pParam);  
    13.   
    14. private:      
    15.     CbFun       pCbFun;     //回调函数指针  
    16.     Tobject*    m_pInstance;    //调用对象  
    17. };  
    18.   
    19. //设置调用对象及其回调函数  
    20. template<typename Tobject, typename Tparam>  
    21. void CCallbackProxy<Tobject, Tparam>::Set(Tobject *pInstance , CbFun pFun)  
    22. {  
    23.     m_pInstance = pInstance;   
    24.     pCbFun = pFun;  
    25. };  
    26.   
    27. //调用回调函数  
    28. template<typename Tobject, typename Tparam>  
    29. bool CCallbackProxy<Tobject, Tparam>::Exec(Tparam* pParam)  
    30. {  
    31.     (m_pInstance->*pCbFun)(pParam);  
    32.     return true;  
    33. }  
    34.   
    35. #endif  


    下面演示下如何使用该类

    test.cpp
    [cpp] view plaincopy
    1. #include "CallbackProxy.h"  
    2.   
    3. class CTest  
    4. {  
    5. public:  
    6.     CTest(int nNum);  
    7.     void CbPrintSum(int *pnAddNum){printf("The Sum is %d\n", m_nSum+*pnAddNum);};  
    8.   
    9. private:  
    10.     int m_nSum;  
    11. };  
    12.   
    13. int main(int argc,  char* argv[])  
    14. {  
    15.     CCallbackProxy<CTest, int> CbProxy;  
    16.   
    17.     CTest TestInstance(20);  
    18.   
    19.     CbProxy.Set(&TestInstance, &CTest::CbPrintSum);  
    20.   
    21.     int nNum = 1000;  
    22.     CbProxy.Exec(&nNum);  
    23.   
    24.     return 0;  
    25. }  
    26.   
    27. CTest::CTest(int nNum):  
    28. m_nSum(nNum)  
    29. {  
    30.   
    31. }