1. 程式人生 > >C++實現的委託機制

C++實現的委託機制

1.引言

下面的委託實現使用的MyGUI裡面的委託實現,MyGUI是一款強大的GUI庫,想理解更多的MyGUI資訊,猛擊這裡http://mygui.info/ 

最終的程式碼可以在這裡下載:http://download.csdn.net/detail/gouki04/3641328  我們的目標是要實現一個跟.NET幾乎完全一樣的委託,使用簡單,支援多播,可以新增刪除委託。同時支援C++的普通函式、模板函式、類成員函式,類的靜態成員函式,並且支援多型。使用方式如下:

  1. // 普通函式
  2. void normalFunc(){ cout << "func1" << endl; }  
  3. class
     Base  
  4. {  
  5. public:  
  6. // 類成員函式
  7. void classFunc(){ cout << "Base func1" << endl; }  
  8. };  
  9. int main()  
  10. {  
  11. Base b;  
  12. CMultiDelegate myDelegate;  
  13. myDelegate += newDelegate(normalFunc);  
  14. myDelegate += newDelegate(&b, &Base::classFunc);  
  15. myDelegate(); // 此時會呼叫normalFunc和classFunc
  16. myDelegate -= newDelegate(&b, &Base::classFunc);  
  17. myDelegate(); // 此時會呼叫normalFunc
  18. return 0;  
  19. }  

2.實現無參函式委託

要實現委託,首先要解決的是封裝C++中的函式指標。因為在C++中,普通函式指標和類成員函式指標是完全不一樣的。如下例子

  1. class CMyClass  
  2. {  
  3. public:  
  4.     void func(int);  
  5. };  
  6. // 定義一個指向CMyClass型別,引數列表為(int),返回值為void的函式指標
  7. typedefvoid (CMyClass::*ClassMethod) (int); // 注意定義時使用了特殊的運算子::*

那麼此函式指標只能指向CMyClass型別的成員函式,不能指向其他類或者普通函式

類成員函式指標不能直接呼叫,要通過一個類例項來呼叫,如下

  1. CMyClass *object = new CMyClass;  
  2. ClassMethod method = CMyClass::func;  
  3. (object->*method)(5); // 注意呼叫時使用了特殊運算子->*

那麼如何封裝呢?我們先來定義下介面吧

(為了簡單起見,下面的實現都是以無參函式為例,後續會講到如何支援任意引數)

  1. class IDelegate  
  2. {  
  3. public:  
  4.     virtual ~IDelegate() { }  
  5.     virtualbool isType(const std::type_info& _type) = 0;  
  6.     virtualvoid invoke() = 0;  
  7.     virtualbool compare(IDelegate *_delegate) const = 0;  
  8. };  

IDelegate類的介面很少,也很簡單,必要介面只有一個,就是invoke,用於觸發函式

但為了可以方便管理,使用了isTypecompare函式來進行相等判斷。

下面是封裝的普通函式指標

  1. class CStaticDelegate : public IDelegate  
  2. {  
  3. public:  
  4.     typedefvoid (*Func)();  
  5.     CStaticDelegate(Func _func) : mFunc(_func) { }  
  6.     virtualbool isType( const std::type_info& _type) { returntypeid(CStaticDelegate) == _type; }  
  7.     virtualvoid invoke() { mFunc(); }  
  8.     virtualbool compare(IDelegate *_delegate) const
  9.     {  
  10.         if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate)) ) returnfalse;  
  11.         CStaticDelegate * cast = static_cast<CStaticDelegate*>(_delegate);  
  12.         return cast->mFunc == mFunc;  
  13.     }  
  14. private:  
  15.     Func mFunc;  
  16. };  

可以看到,CStaticDelegate只是簡單地封裝了普通函式指標,程式碼也非常簡單

(類的某些成員函式,如isTypecompare使用了RTTI

好了,注意了,下面開始封裝類成員函式指標

  1. template<class T>  
  2. class CMethodDelegate : public IDelegate  
  3. {  
  4. public:  
  5.     typedefvoid (T::*Method)();  
  6.     CMethodDelegate(T * _object, Method _method) : mObject(_object), mMethod(_method) { }  
  7.     virtualbool isType( const std::type_info& _type) { returntypeid(CMethodDelegate) == _type; }  
  8.     virtualvoid invoke()  
  9.     {  
  10.         (mObject->*mMethod)();  
  11.     }  
  12.     virtualbool compare(IDelegate *_delegate) const
  13.     {  
  14.         if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate)) ) returnfalse;  
  15.         CMethodDelegate* cast = static_cast<CMethodDelegate* >(_delegate);  
  16.         return cast->mObject == mObject && cast->mMethod == mMethod;  
  17.     }  
  18. private:  
  19.     T * mObject;  
  20.     Method mMethod;  
  21. };  

首先解釋一下:因為類成員函式指標與類的型別有關,不同類的成員函式指標是不一樣的。

要解決型別不同,很簡單,使用模板就行。

程式碼跟CStaticDelegate基本一樣,下面稍微解釋一下:

CMethodDelegate類主要封裝了一個類例項指標以及類成員函式的指標

這樣在invoke時就不要額外的通過一個類例項了

要注意一點,compare函式的實現中,相等判定是類例項以及類函式指標都一樣。

也就是說就算是指標同一個成員函式,但例項不同,委託就不同

為了方便使用,定義函式newDelegate來建立委託使用的函式

  1. inline IDelegate* newDelegate( void (*_func)() )  
  2. {  
  3.     returnnew CStaticDelegate(_func);  
  4. }  
  5. template<class T>  
  6. inline IDelegate* newDelegate( T * _object, void (T::*_method)() )  
  7. {  
  8.     returnnew CMethodDelegate<T>(_object, _method);  
  9. }  

至此,對C++函式指標的封裝就完成了,不難吧。

下面就是委託的實現了

  1. class CMultiDelegate  
  2. {  
  3. public:  
  4.     typedef std::list<IDelegate*> ListDelegate;  
  5.     typedef ListDelegate::iterator ListDelegateIterator;  
  6.     typedef ListDelegate::const_iterator ConstListDelegateIterator;  
  7.     CMultiDelegate () { }  
  8.     ~CMultiDelegate () { clear(); }  
  9.     bool empty() const
  10.     {  
  11.         for (ConstListDelegateIterator iter = mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)  
  12.         {  
  13.             if (*iter) returnfalse;  
  14.         }  
  15.         returntrue;  
  16.     }  
  17.     void clear()  
  18.     {  
  19.         for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)  
  20.         {  
  21.             if (*iter)  
  22.             {  
  23.                 delete (*iter);  
  24.                 (*iter) = 0;  
  25.             }  
  26.         }  
  27.     }  
  28.     CMultiDelegate& operator+=(IDelegate* _delegate)  
  29.     {  
  30.         for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)  
  31.         {  
  32.             if ((*iter) && (*iter)->compare(_delegate))  
  33.             {  
  34.                 delete _delegate;  
  35.                 return *this;  
  36.             }  
  37.         }  
  38.         mListDelegates.push_back(_delegate);  
  39.         return *this;  
  40.     }  
  41.     CMultiDelegate& operator-=(IDelegate* _delegate)  
  42.     {  
  43.         for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)  
  44.         {  
  45.             if ((*iter) && (*iter)->compare(_delegate))  
  46.             {  
  47.                 if ((*iter) != _delegate) delete (*iter);  
  48.                 (*iter) = 0;  
  49.                 break;  
  50.             }  
  51.         }  
  52.         delete _delegate;  
  53.         return *this;  
  54.     }  
  55.     void operator()( )  
  56.     {  
  57.         ListDelegateIterator iter = mListDelegates.begin();  
  58.         while (iter != mListDelegates.end())  
  59.         {  
  60.             if (0 == (*iter))  
  61.             {  
  62.                 iter = mListDelegates.erase(iter);  
  63.             }  
  64.             else
  65.             {  
  66.                 (*iter)->invoke();  
  67.                 ++iter;  
  68.             }  
  69.         }  
  70.     }  
  71. private:  
  72.     CMultiDelegate (const CMultiDelegate& _event);  
  73.     CMultiDelegate& operator=(const CMultiDelegate& _event);  
  74. private:  
  75.     ListDelegate mListDelegates;  
  76. };  

仔細理解下CMultiDelegate類的實現,程式碼都不深奧。

比較重要的是3個函式 :+=-=()運算子的過載函式

+= 用於新增一個委託函式

-= 用於去掉一個委託函式

() 用於觸發委託函式

差不多就是普通的stl容器使用了。

這裡要重點說明的一點是,大家仔細看 += 函式的實現中

  1. if ((*iter) && (*iter)->compare(_delegate))  
  2. {  
  3. delete _delegate; // 如果該委託函式已經被添加了,則delete掉外部的_delegate
  4. return *this;  
  5. }  

為什麼要delete掉外部的指標呢?

因為C++的記憶體洩露一直是個麻煩事,所以MyUGI的委託裡,所有的委託函式統一由Delegate本身管理

外部不要自己newdelete委託函式,也不要儲存一個委託函式,Delegate本身會管理好的。

建議像如下使用:

  1. CMultiDelegate myDelegate;  
  2. myDelegate += newDelegate(normalFunc);  
  3. myDelegate -= newDelegate(normalFunc);  

而不建議像如下使用:

  1. CMultiDelegate myDelegate;  
  2. IDelegate* delegateFunc = newDelegate(normalFunc);  
  3. myDelegate += delegateFunc;  
  4. myDelegate -= delegateFunc;  

上面2種方法都沒錯,都不會造成記憶體洩露

你可能會覺得第2種方法減少new的次數,比第一種方法更好。其實不然,因為第2種方法有個很大的隱患

  1. myDelegate -= delegateFunc; // 在這一步,delegateFunc所指向的空間已經被釋放掉了(在-=函式裡面)

所以如果你後面又想將delegateFunc新增到myDelegate裡面時,你就不能再這樣用了

  1. myDelegate += delegateFunc; // 錯誤,因為delegateFunc的空間已經被釋放了

你得重新new一個

delegateFunc = newDelegate(normalFunc);

myDelegate += delegateFunc;

相信你不會願意這樣做的,因為這種方法很容易造成記憶體洩露或者崩潰

現在你應該可以明白 -= 函式是怎麼釋放委託函式記憶體了吧。

1.實現任意引數的函式委託

按上一篇文章的方法,你已經可以使用無引數的函式委託了。當然,這遠遠不夠。要實現任意引數的函式委託,這裡的任意引數包括任意個數和任意型別。任意型別這個容易解決,使用模板就行,但任意引數個數呢?

只能不同個數各實現一個類,如

  1. // 單參函式委託
  2. template<typename TP1>  
  3. class CMultiDelegate1{};  
  4. // 雙參函式委託
  5. template<typename TP1, typename TP2>  
  6. class CMultiDelegate2{};  

注意類名是不一樣的,分別為CMultiDelegate1CMultiDelegate2

C++裡面,類名相同但模板引數個數不同是會當成一個類對待的,所以那樣編譯不過的

這樣是不是很麻煩呢?

不是很麻煩,是相當麻煩。因為不單單是CMultiDelegate要實現多個引數的版本

IDelegateCStaticDelegateCMethodDelegate都要實現對應的多個引數的版本!

其實所有版本的內部實現幾乎一樣,下面給出雙參函式的版本

  1. template<typename TP1, typename TP2>  
  2. class IDelegate2  
  3. {  
  4. public:  
  5.     virtual ~IDelegate2() { }  
  6.     virtualbool isType( const std::type_info& _type) = 0;  
  7.     virtualvoid invoke( TP1 p1, TP2 p2 ) = 0;  
  8.     virtualbool compare( IDelegate2<typename TP1, typename TP2> *_delegate) const = 0;  
  9. };  
  10. template<typename TP1, typename TP2>  
  11. class CStaticDelegate2 : public  IDelegate2<typename TP1, typename TP2>  
  12. {  
  13. public:  
  14.     typedefvoid (*Func)( TP1 p1, TP2 p2 );  
  15.     CStaticDelegate2 (Func _func) : mFunc(_func) { }  
  16.     virtualbool isType( const std::type_info& _type) { returntypeid( CStaticDelegate2<typename TP1, typename TP2> ) == _type; }  
  17.     virtualvoid invoke( TP1 p1, TP2 p2 )  
  18.     {  
  19.         mFunc( p1, p2 );  
  20.     }  
  21.     virtualbool compare( IDelegate2<typename TP1, typename TP2> *_delegate) const
  22.     {  
  23.         if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate2 <typename TP1, typename TP2>)) ) returnfalse;  
  24.         CStaticDelegate2 <typename TP1, typename TP2> * cast = static_cast<CStaticDelegate2 <typename TP1, typename TP2> *>(_delegate);  
  25.         return cast->mFunc == mFunc;  
  26.     }  
  27.     virtualbool compare(IDelegateUnlink * _unlink) const { returnfalse; }  
  28. private:  
  29.     Func mFunc;  
  30. };  
  31. template <typename T, typename TP1, typename TP2>  
  32. class CMethodDelegate2 : public  IDelegate2 <typename TP1, typename TP2>  
  33. {  
  34. public:  
  35.     typedefvoid (T::*Method)( TP1 p1, TP2 p2 );  
  36.     CMethodDelegate2(T * _object, Method _method) : mObject(_object), mMethod(_method) { }  
  37.     virtualbool isType( const std::type_info& _type) { returntypeid( CMethodDelegate2 <T, TP1, TP2> ) == _type; }  
  38.     virtualvoid invoke( TP1 p1, TP2 p2 )  
  39.     {  
  40.         (mObject->*mMethod)( p1, p2 );  
  41.     }  
  42.     virtualbool compare(  IDelegate2 <typename TP1, typename TP2>  * _delegate) const
  43.     {  
  44.         if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate2 <T, TP1, TP2>)) ) returnfalse;  
  45.         CMethodDelegate2 <T, TP1, TP2>  * cast = static_cast<  CMethodDelegate2 <T, TP1, TP2>  * >(_delegate);  
  46.         return cast->mObject == mObject && cast->mMethod == mMethod;  
  47.     }  
  48. private:  
  49.     T * mObject;  
  50.     Method mMethod;  
  51. };  
  52. template   <typename TP1, typename TP2>  
  53. inline  delegates::IDelegate2 <typename TP1, typename TP2>  * newDelegate( void (*_func)( TP1 p1, TP2 p2 ) )  
  54. {  
  55.     returnnew delegates::CStaticDelegate2 <typename TP1, typename TP2>  (_func);  
  56. }  
  57. template <typename T, typename TP1, typename TP2>  
  58. inline  delegates::IDelegate2 <typename TP1, typename TP2>  * newDelegate( T * _object, void (T::*_method)( TP1 p1, TP2 p2 ) )  
  59. {  
  60.     returnnew delegates::CMethodDelegate2  <T, TP1, TP2>  (_object, _method);  
  61. }  
  62. template   <typename TP1, typename TP2>  
  63. class CMultiDelegate2  
  64. {  
  65. public:  
  66.     typedef IDelegate2 <typename TP1, typename TP2>  IDelegate;  
  67.     typedeftypename std::list<IDelegate*> ListDelegate;  
  68.     typedeftypename ListDelegate::iterator ListDelegateIterator;  
  69.     typedeftypename ListDelegate::const_iterator ConstListDelegateIterator;  
  70.     CMultiDelegate2 () { }  
  71.     ~CMultiDelegate2 () { clear(); }  
  72.     bool empty() const
  73.     {  
  74.         for (ConstListDelegateIterator iter = mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)  
  75.         {  
  76.             if (*iter) returnfalse;  
  77.         }  
  78.         returntrue;  
  79.     }  
  80.     void clear()  
  81.     {  
  82.         for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)  
  83.         {  
  84.             if (*iter)  
  85.             {  
  86.                 delete (*iter);  
  87.                 (*iter) = 0;  
  88.             }  
  89.         }  
  90.     }  
  91.     CMultiDelegate2  <typename TP1, typename TP2> & operator+=(IDelegate* _delegate)  
  92.     {  
  93.         for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)  
  94.         {  
  95.             if ((*iter) && (*iter)->compare(_delegate))  
  96.             {  
  97.                 delete _delegate;  
  98.                 return *this;  
  99.                 //MYGUI_ASSERT(false, "dublicate delegate");
  100.             }  
  101.         }  
  102.         mListDelegates.push_back(_delegate);  
  103.         return *this;  
  104.     }  
  105.     CMultiDelegate2  <typename TP1, typename TP2> & operator-=(IDelegate* _delegate)  
  106.     {  
  107.         for (ListDelegateIterator iter=mListDelegates.begin(); iter!=mListDelegates.end(); ++iter)  
  108.         {  
  109.             if ((*iter) && (*iter)->compare(_delegate))  
  110.             {  
  111.                 if ((*iter) != _delegate) delete (*iter);  
  112.                 (*iter) = 0;  
  113.                 break;  
  114.             }  
  115.         }  
  116.         delete _delegate;  
  117.         return *this;  
  118.     }  
  119.     void operator()( TP1 p1, TP2 p2 )  
  120.     {  
  121.         ListDelegateIterator iter = mListDelegates.begin();  
  122.         while (iter != mListDelegates.end())  
  123.         {  
  124.             if (0 == (*iter))  
  125.             {  
  126.                 iter = mListDelegates.erase(iter);  
  127.             }  
  128.             else
  129.             {  
  130.                 (*iter)->invoke( p1, p2 );  
  131.                 ++iter;  
  132.             }  
  133.         }  
  134.     }  
  135. private:  
  136.     CMultiDelegate2 (const CMultiDelegate2  <typename TP1, typename TP2> & _event);  
  137.     CMultiDelegate2<typename TP1, typename TP2> & operator=(const CMultiDelegate2<typename TP1, typename TP2> & _event);  
  138. private:  
  139.     ListDelegate mListDelegates;  
  140. };  

當然放心啦,不會讓大家將不同引數的版本各寫一遍的

下面要介紹的是MyGUI的解決方法,一個利用預編譯和標頭檔案重複編譯的方法(很有意思的)

我們一般寫標頭檔案時,都會加上防止標頭檔案重複編譯的程式碼,如

  1. #ifndef __XXX_H__
  2. #define __XXX_H__
  3. // ..類宣告等
  4. #endif

這裡我們就要反其道而行,去掉防止重複編譯的程式碼,然後重複包含這個標頭檔案,但每次其編譯的都是不同引數個數的版本

第一次編譯的是無參的,第二次是單參的,第三次是雙參.....一直到你想要支援的引數個數

那怎麼讓其每次編譯的都不同呢?

答案就是使用強大的預編譯:巨集

下面給出單參的IDelegate的例子

首先定義以下巨集:

  1. #define DELEGATE_TEMPLATE template
  2. #define DELEGATE_TEMPLATE_PARAMS <typename TP1>
  3. #define DELEGATE_TEMPLATE_ARGS TP1 p1
  4. #define MYGUI_I_DELEGATE IDelegate1

那麼下面這段程式碼就會編譯出單參的IDelegate版本

  1. DELEGATE_TEMPLATE   DELEGATE_TEMPLATE_PARAMS  
  2. class MYGUI_I_DELEGATE  
  3. {  
  4. public:  
  5.     virtual ~MYGUI_I_DELEGATE() { }  
  6.     virtualbool isType( const std::type_info& _type) = 0;  
  7.     virtualvoid invoke( DELEGATE_PARAMS ) = 0;  
  8.     virtualbool compare(  MYGUI_I_DELEGATE DELEGATE_TEMPLATE_ARGS  * _delegate) const = 0;  
  9. };  

神奇吧,這裡使用的可以說是巨集實現的多型。

在這段程式碼編譯完了之後,將所有巨集都undefine掉,如

  1. #undef DELEGATE_TEMPLATE
  2. #undef DELEGATE_TEMPLATE_PARAMS
  3. #undef DELEGATE_TEMPLATE_ARGS
  4. #undef MYGUI_I_DELEGATE

再重新定義雙參版本的,如

  1. #define DELEGATE_TEMPLATE template
  2. #define DELEGATE_TEMPLATE_PARAMS <typename TP1, typename TP2>
  3. #define DELEGATE_TEMPLATE_ARGS TP1 p1, TP2 p2
  4. #define MYGUI_I_DELEGATE IDelegate2

那麼編譯出來的就是雙參的版本了!

使用這種方法就可以將其他的如CStaticDelegateCMethodDelegateCMultiDelegate的各種版本都實現了,

而你要做的僅是重新define下那些巨集就行了,夠方便了吧。

下一篇文章將會介紹MyGUI實現的一些輔助類,如單委託和DelegateUnlink。並給出一個測試例子,測試該委託機制對C++各種函式的支援。

1.引言

按上一篇文章的方法,你已經可以使用任意引數的函式委託了。這裡介紹下MyGUI實現的兩個輔助類,CDelegate類和IDelegateUnlink。如果你不為了深入瞭解MyGUI的委託實現,可以跳過此處。CDelegate即為單委託,實際效果跟函式指標差不多,於CMultiDelegate的區別在於其不支援多播。而IDelegateUnlink類主要是在CMultiDelegate中使用,在多播下一次性去掉自身的所有委託。


2.單委託

  1. // 無參的單委託實現
  2. class CDelegate  
  3. {  
  4. public:  
  5.     typedef CDelegate IDelegate;  
  6.     CDelegate () : mDelegate(0) { }  
  7.     CDelegate (const CDelegate& _event)  
  8.     {  
  9.         // 在拷貝構造時,將被拷貝的委託去掉,即委託只存在一份
  10.         mDelegate = _event.mDelegate;  
  11.         const_cast<CDelegate&>(_event).mDelegate = 0;  
  12.     }  
  13.     ~CDelegate () { clear(); }  
  14.     bool empty() const { return mDelegate == 0; }  
  15.     void clear()  
  16.     {  
  17.         if (mDelegate)  
  18.         {  
  19.             delete mDelegate;  
  20.             mDelegate = 0;  
  21.         }  
  22.     }  
  23.     CDelegate & operator=(IDelegate* _delegate)  
  24.     {  
  25.         delete mDelegate;  
  26.         mDelegate = _delegate;  
  27.         return *this;  
  28.     }  
  29.     CDelegate & operator=(const CDelegate& _event)  
  30.     {  
  31.         // 在賦值時,將右值的委託去掉,即委託只存在一份
  32.         delete mDelegate;  
  33.         mDelegate = _event.mDelegate;  
  34.         const_cast<CDelegate&>(_event).mDelegate = 0;  
  35.         return *this;  
  36.     }  
  37.     void operator()( )  
  38.     {  
  39.         if (mDelegate == 0) return;  
  40.         mDelegate->invoke( );  
  41.     }  
  42. private:  
  43.     IDelegate * mDelegate;  
  44. };  

可以看到,單委託只實現了 = 運算子,沒有實現 += 運算子。
而且在賦值時會將原委託去掉,確保只有一份委託。
其實單委託跟普通函式指標差不多,在使用單委託的地方可以換成使用普通函式指標。


3.斷開委託

  1. // 斷開委託的基類
  2. class IDelegateUnlink  
  3. {  
  4. public:  
  5.     virtual ~IDelegateUnlink() { }  
  6.     IDelegateUnlink() { m_baseDelegateUnlink = this; }  
  7.     bool compare(IDelegateUnlink * _unlink) const { return m_baseDelegateUnlink == _unlink->m_baseDelegateUnlink; }  
  8. private:  
  9.     IDelegateUnlink * m_baseDelegateUnlink;  
  10. };  

所謂斷開委託,只能用在多重委託,即CMultiDelegate中,可以斷開自身與其相連的所有委託。
使用方法就在將自身的類從IDelegateUnlink派生,然後使用CMultiDelegate中的clear函式即可斷開委託。
在下面會有例子說明。


4.測試

  1. /* 測試Delegate對不同函式的支援 
  2.  * 可以參考下不同函式的使用方式 
  3.  */
  4. #include "delegate.h"
  5. #include <iostream>
  6. usingnamespace std;  
  7. // 普通函式1
  8. void func(int a, int b)  
  9. {  
  10.     cout << "func(" << a << ", " << b << ")" << endl;  
  11. }  
  12. // 普通函式2
  13. void func2(int a, int b)  
  14. {  
  15.     cout << "func2(" << a << ", " << b << ")" << endl;  
  16. }  
  17. // 普通類
  18. class NormalClass  
  19. {  
  20. public:  
  21.     // 類的普通成員函式
  22.     void normalFunc(int a, int b)  
  23.     {  
  24.         cout << "NormalClass::normalFunc(" << a << ", " << b << ")" << endl;  
  25.     }  
  26. };  
  27. // 實現了IDelegateUnlink的類
  28. class BaseUnlinkClass : public delegates::IDelegateUnlink  
  29. {  
  30. public:  
  31.     // 類的虛擬函式
  32.     virtualvoid virFunc(int a, int b)  
  33.     {  
  34.         cout << "BaseUnlinkClass::virFunc(" << a << ", " << b << ")" << endl;  
  35.     }  
  36.     // 類的普通成員函式
  37.     void normalFunc(int a, int b)  
  38.     {  
  39.         cout << "BaseUnlinkClass::normalFunc(" << a << ", " << b << ")" << endl;  
  40.     }  
  41. };  
  42. class DerivedClass : public BaseUnlinkClass  
  43. {  
  44. public:  
  45.     // 類的虛擬函式
  46.     virtualvoid virFunc(int a, int b)  
  47.     {  
  48.         cout << "DerivedClass::virFunc(" << a << ", " << b << ")" << endl;  
  49.     }  
  50.     // 類的靜態成員函式
  51.     staticvoid staticFunc(int a, int b)  
  52.     {  
  53.         cout << "DerivedClass::staticFunc(" << a << ", " << b << ")" << endl;  
  54.     }  
  55. };  
  56. // 模板函式
  57. template<class T>  
  58. void TFunc(T a, T b)  
  59. {  
  60.     cout << "TFunc(" << a << ", " << b << ")" << endl;  
  61. }  
  62. int main()  
  63. {  
  64.     BaseUnlinkClass *baseUnlinkClass = new BaseUnlinkClass;  
  65.     DerivedClass *derivedClass = new DerivedClass;  
  66.     NormalClass *normalClass = new NormalClass;  
  67.     // 定義委託
  68.     typedef delegates::CMultiDelegate2<intint> EvenetHandler;  
  69.     EvenetHandler event;  
  70.     // 新增普通函式
  71.     event += newDelegate(func);  
  72.     event += newDelegate(func2);  
  73.     // 新增類的普通成員函式
  74.     event += newDelegate(normalClass, &NormalClass::normalFunc);  
  75.     event += newDelegate(baseUnlinkClass, &BaseUnlinkClass::normalFunc);  
  76.     // 新增類的虛擬函式
  77.     event += newDelegate(baseUnlinkClass, &BaseUnlinkClass::virFunc);  
  78.     event += newDelegate(derivedClass, &DerivedClass::virFunc);  
  79.     // 注意在多型下,使用基類指標時,函式指標要用基類的函式指標,不能用派生類的
  80.     // 但是在呼叫時會響應多型,也就是會呼叫派生類的虛擬函式
  81.     event += newDelegate((BaseUnlinkClass*)derivedClass, &BaseUnlinkClass::virFunc);  
  82.     // 新增類的靜態成員函式
  83.     event += newDelegate(&DerivedClass::staticFunc);  
  84.     // 新增模板函式
  85.     event += newDelegate(TFunc<int>);  
  86.     // 觸發事件
  87.     event(1, 2);  
  88.     cout << endl;  
  89.     // 去掉函式
  90.     event -= newDelegate(func);  
  91.     // 去掉baseUnlinkClass所有的函式
  92.     event.clear(baseUnlinkClass);  
  93.     // 去掉derivedClass所有的函式
  94.     // 注意靜態成員函式staticFunc不會去掉
  95.     event.clear(derivedClass);  
  96.     //event.clear(normalClass);
  97.     // 錯誤呼叫,normalClass不是IDelegateUnlink的派生類
  98.     // 不能使用clear去掉自身的函式
  99.     // 應該使用如下方法
  100.     event -= newDelegate(normalClass, &NormalClass::normalFunc);  
  101.     // 觸發事件
  102.     event(2, 3);  
  103.     cout << endl;  
  104.     return 0;  
  105. }  

相關推薦

C++實現委託機制(一)

1.引言:              如果你接觸過C#,你就會覺得C#中的delegate(委託)十分靈巧,它的用法上和C\C++的函式指標很像,但是卻又比C\C++的函式指標更加靈活。並且委託可以一對多,也就是可以註冊多個函式,甚至是某個類的非靜態成員函式。而實現事件訊息

C++實現 反射 機制( 即根據 類名 建立 類例項)Create C++ Object Dynamically

Create C++ Object Dynamically Introduction C++不像C#和Java那樣具有反射的能力,通常不能根據任意一個class name來建立該class的instance。但我們知道在MFC中,任何繼承了CObject的類都可以根據其名字來建立例項,它是使用了一些巨集。而

【Unity基於C#事件委託機制,最輕鬆易懂的版本,一個例項解決你的困惑】

PS:題主涉世尚淺,如有不對的地方還請大佬指出~ 對於C#的委託和事件機制,看似複雜抽象,但其邏輯條理十分清晰,所以理解起來也不會太難,關鍵在於瞭解它兩的聯絡,以及工作原理。 委託 觀察者模式: 定義了物件之間的一對多依賴,這樣一來,當一個物件改變狀態時

C++實現委託機制

1.引言 下面的委託實現使用的MyGUI裡面的委託實現,MyGUI是一款強大的GUI庫,想理解更多的MyGUI資訊,猛擊這裡http://mygui.info/  最終的程式碼可以在這裡下載:http://download.csdn.net/detail/gouki04/3

C#使用委託和事件實現釋出訂閱者模式

事件是C#中的高階概念,和js中的滑鼠點選$("tag").click,懸停$("tag").hover或css元素樣式的改變(onChanged)等事件,當事件觸發才執行我們所委託的方法。 步驟: 1、建立一個委託; 2、將建立的委託與特定事件關聯; 3、編寫C#事件處理程式; 4、利用編

C#實現軟體授權,限定MAC執行(軟體license管理,簡單軟體註冊機制

最近做了一個綠色免安裝軟體,領導臨時要求加個註冊機制,不能讓現場工程師隨意複製。事出突然,只能在現場開發(離開現場軟體就不受我們控了)。花了不到兩個小時實現了簡單的註冊機制,稍作整理。 基本原理:1.軟體一執行就把計算機的CPU、主機板、BIOS、MAC地址記錄下來,然後加密(key=key1)生成

C#委託機制筆記

首先要明確委託機制 根據查閱的資料描述,委託相當於C語言的指標,函式指標代表函式在flash中的地址,入口。 但是委託是面向物件的型別安全,具有保障,故而需要一些繁瑣的定義,宣告,例項之後才可以使用,使用時作為引數傳遞,是引用傳遞。 委託的例項化中的引數,即委託的方法既可以

C++實現反射(即類似於.NET、java的反射機制)

NET下的很多技術都是基於反射機制來實現的,反射讓.NET平臺下的語言變得得心應手。最簡單的,比如列舉型別,我們我可以很容易的獲得一個列舉變數的數值以及其名稱字串。 可是,在C++中,列舉變數本質上和一個整形變數沒有區別,我們很難獲取一個列舉變數的名稱字串。 其實在C++中,我們可以通過巨集

c++ 帶引數的巨集定義實現反射機制

lua 這種指令碼語言用久了,總覺得反射機制就應該理所當然的嵌入在語言特性裡。 比如希望根據自己傳的型別名變數,動態去 new 一些例項。在 lua ,js 裡做起來就非常簡單,然而在 c++裡面做起來,就需要稍微費些周折。 好在 c++ 巨集定義 支援傳入引數

Unity3D 利用C#實現簡單的代理模式Delegate(委託

Ref: http://www.cnblogs.com/shadow7/p/5892641.html 1、Delegate是什麼? Delegate中文翻譯為“委託”。 C#語言是支援代理的,

cc++相互呼叫機制分析與實現

c++通常被稱為Better c,多數是因為c++程式可以很簡單的呼叫c函式,語法上基本實現相容。最常用的呼叫方式就是c++模組呼叫c實現的dll匯出函式,很簡單的用法,使用extern "C"將c標頭檔案或者函式修飾下。 本文主要涉及到在c模組中如何呼叫c++函式,或者換個名字,extern

c++函式過載機制實現原理

一、c++函式過載的定義: 在同一作用域類,一組函式的函式名相同,引數列表不同(引數個數不同/引數型別不同),返回值可同可不同 二、函式過載的作用: 過載函式通常用來在同一個作用域內 用同一個函式名 命名一組功能相似的函式,這樣做減少了函式名的數量,避

C# 使用委託實現非同步程式設計的四種方式

一、關於委託 1、委託概念:委託是一個類,它定義了方法的型別,使得可以將方法當作另一個方法的引數來進行傳遞      個人角色這個概念有些晦澀難懂,大家可以把委託當成一個方法的指標就好了,可以指向一個方法。或者通過(+=)的方式指向多個。 2、四種宣告方式 1)直接用del

C# 使用委託實現多執行緒呼叫窗體的四種方式

1、方法一:使用執行緒      功能描述:在用c#做WinFrom開發的過程中。我們經常需要用到進度條(ProgressBar)用於顯示進度資訊。這時候我們可能就需要用到多執行緒,如果不採用多執行緒控制進度條,視窗很容易假死(無法適時看到進度資訊)。下面

c#使用委託實現辛普森法求多個函式的定積分

用辛普生法對幾個不同的被積函式求指定區間的定積分。被積函式為f(x),積分割槽間[a,b]被等分為n=2k份,每份步長為h=(b-a)/n,則積分值為:S≈h((f(a)+f(b))/2 +f(a+h)+…+f(a+(n-1)h))。 執行結果:

c# 用委託和事件實現不同窗體間的通訊(一)

 C# 中的“事件”是當物件滿足一定條件,發生某些事情時,類向該類的客戶提供通知的一種方法。使用事件,擁有該事件的物件不必知道需要通知誰,一旦滿足了某個條件,將自動呼叫該事件,正確通知每個需要通知的物件。通過使用事件,提高了程式的模組化程度。    例子:通過form1開啟f

利用Objective-C的反射機制和執行時特性實現類靜態方法的動態訪問(一)

如題,灑家今天在搭建蘋果手機APP開發框架中遇到一個坑爹問題,折騰了半天,總算研究出來了,特記錄如下: 1、先說具體需求,本人實現了一個自定義檢視控制元件,通過KVC特性先從plist配置檔案中讀取資料,轉換成模型物件,然後根據模型物件動態建立檢視物件,這時就需要用到Obj

C++實現簡單的反射機制

備忘記錄下來。 程式碼如下: 巨集定義REGISTER解讀: 這個巨集做了兩件事情, 第一件事情是聲明瞭一個函式,即 className* objectCreator##classNam

實現C++ 列舉反射機制

上一階段寫了一些功能需要列舉反射機制,但是C++不支援,很無奈。最近又遇到這個問題,所以自己實現了一版, 自己的版本 列舉定義是 巨集定義,其他的都是一些解析 程式碼如下: 第一次貼程式碼,也不太會 //enum_map.h標頭檔案 </pre><p&g

C++ 模仿Android實現Handler機制

前言:        一直使用android的Handler,感覺非常好用,但是當我使用C++程式設計時,想使用Android Handler一樣的程式設計模式,竟不知如何下手,網上找了很久,都沒找到具體的實現,能搜尋到MFC中使用handler,但是一直不搞windows的