天天看點

C++實作的委托機制轉載 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. typedef void (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.     virtual bool isType(const std::type_info& _type) = 0;  
  6.     virtual void invoke() = 0;  
  7.     virtual bool compare(IDelegate *_delegate) const = 0;  
  8. };  

IDelegate類的接口很少,也很簡單,必要接口隻有一個,就是invoke,用于觸發函數

但為了可以友善管理,使用了isType和compare函數來進行相等判斷。

下面是封裝的普通函數指針

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

可以看到,CStaticDelegate隻是簡單地封裝了普通函數指針,代碼也非常簡單

(類的某些成員函數,如isType和compare使用了RTTI,

對C++的動态類型判斷不熟的可以猛擊這裡http://blog.csdn.net/gouki04/article/details/6796173)

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

  1. template<class T>  
  2. class CMethodDelegate : public IDelegate  
  3. {  
  4. public:  
  5.     typedef void (T::*Method)();  
  6.     CMethodDelegate(T * _object, Method _method) : mObject(_object), mMethod(_method) { }  
  7.     virtual bool isType( const std::type_info& _type) { return typeid(CMethodDelegate) == _type; }  
  8.     virtual void invoke()  
  9.     {  
  10.         (mObject->*mMethod)();  
  11.     }  
  12.     virtual bool compare(IDelegate *_delegate) const  
  13.     {  
  14.         if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate)) ) return false;  
  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.     return new CStaticDelegate(_func);  
  4. }  
  5. template<class T>  
  6. inline IDelegate* newDelegate( T * _object, void (T::*_method)() )  
  7. {  
  8.     return new 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) return false;  
  14.         }  
  15.         return true;  
  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本身管理

外部不要自己new或delete委托函數,也不要儲存一個委托函數,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.實作任意參數的函數委托

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

注:最終的實作代碼可以在這裡下載下傳:http://download.csdn.net/detail/gouki04/3641328

隻能不同個數各實作一個類,如

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

注意類名是不一樣的,分别為CMultiDelegate1和CMultiDelegate2

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

這樣是不是很麻煩呢?

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

連IDelegate、CStaticDelegate和CMethodDelegate都要實作對應的多個參數的版本!

其實所有版本的内部實作幾乎一樣,下面給出雙參函數的版本

  1. template<typename TP1, typename TP2>  
  2. class IDelegate2  
  3. {  
  4. public:  
  5.     virtual ~IDelegate2() { }  
  6.     virtual bool isType( const std::type_info& _type) = 0;  
  7.     virtual void invoke( TP1 p1, TP2 p2 ) = 0;  
  8.     virtual bool 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.     typedef void (*Func)( TP1 p1, TP2 p2 );  
  15.     CStaticDelegate2 (Func _func) : mFunc(_func) { }  
  16.     virtual bool isType( const std::type_info& _type) { return typeid( CStaticDelegate2<typename TP1, typename TP2> ) == _type; }  
  17.     virtual void invoke( TP1 p1, TP2 p2 )  
  18.     {  
  19.         mFunc( p1, p2 );  
  20.     }  
  21.     virtual bool compare( IDelegate2<typename TP1, typename TP2> *_delegate) const  
  22.     {  
  23.         if (0 == _delegate || !_delegate->isType(typeid(CStaticDelegate2 <typename TP1, typename TP2>)) ) return false;  
  24.         CStaticDelegate2 <typename TP1, typename TP2> * cast = static_cast<CStaticDelegate2 <typename TP1, typename TP2> *>(_delegate);  
  25.         return cast->mFunc == mFunc;  
  26.     }  
  27.     virtual bool compare(IDelegateUnlink * _unlink) const { return false; }  
  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.     typedef void (T::*Method)( TP1 p1, TP2 p2 );  
  36.     CMethodDelegate2(T * _object, Method _method) : mObject(_object), mMethod(_method) { }  
  37.     virtual bool isType( const std::type_info& _type) { return typeid( CMethodDelegate2 <T, TP1, TP2> ) == _type; }  
  38.     virtual void invoke( TP1 p1, TP2 p2 )  
  39.     {  
  40.         (mObject->*mMethod)( p1, p2 );  
  41.     }  
  42.     virtual bool compare(  IDelegate2 <typename TP1, typename TP2>  * _delegate) const  
  43.     {  
  44.         if (0 == _delegate || !_delegate->isType(typeid(CMethodDelegate2 <T, TP1, TP2>)) ) return false;  
  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.     return new 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.     return new 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.     typedef typename std::list<IDelegate*> ListDelegate;  
  68.     typedef typename ListDelegate::iterator ListDelegateIterator;  
  69.     typedef typename 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) return false;  
  77.         }  
  78.         return true;  
  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.     virtual bool isType( const std::type_info& _type) = 0;  
  7.     virtual void invoke( DELEGATE_PARAMS ) = 0;  
  8.     virtual bool 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  

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

使用這種方法就可以将其他的如CStaticDelegate、CMethodDelegate和CMultiDelegate的各種版本都實作了,

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