1.引言
下面的委托實現使用的MyGUI裡面的委托實現,MyGUI是一款強大的GUI庫,想理解更多的MyGUI信息,猛擊這裡。
我們的目標是要實現一個跟.NET幾乎完全一樣的委托,使用簡單,支持多播,可以添加刪除委托。同時支持C++的普通函數、模板函數、類成員函數,類的靜態成員函數,並且支持多態。
最終的代碼可以在這裡下載:
免費下載地址在 http://linux.linuxidc.com/
用戶名與密碼都是www.linuxidc.com
具體下載目錄在 /2012年資料/8月/19日/C++實現的委托機制
使用方式如下:
2.實現無參函數委托
要實現委托,首先要解決的是封裝C++中的函數指針。因為在C++中,普通函數指針和類成員函數指針是完全不一樣的。如下例子
那麼此函數指針只能指向CMyClass類型的成員函數,不能指向其他類或者普通函數
類成員函數指針不能直接調用,要通過一個類實例來調用,如下
那麼如何封裝呢?我們先來定義下接口吧
(為了簡單起見,下面的實現都是以無參函數為例,後續會講到如何支持任意參數)
IDelegate類的接口很少,也很簡單,必要接口只有一個,就是invoke,用於觸發函數
但為了可以方便管理,使用了isType和compare函數來進行相等判斷。
下面是封裝的普通函數指針
可以看到,CStaticDelegate只是簡單地封裝了普通函數指針,代碼也非常簡單
(類的某些成員函數,如isType和compare使用了RTTI,
對C++的動態類型判斷不熟的可以猛擊這裡 http://www.linuxidc.com/Linux/2012-08/68655.htm )
好了,注意��,下面開始封裝類成員函數指針
首先解釋一下:因為類成員函數指針與類的類型有關,不同類的成員函數指針是不一樣的。
要解決類型不同,很簡單,使用模板就行。
代碼跟CStaticDelegate基本一樣,下面稍微解釋一下:
CMethodDelegate類主要封裝了一個類實例指針以及類成員函數的指針
這樣在invoke時就不要額外的通過一個類實例了
要注意一點,compare函數的實現中,相等判定是類實例以及類函數指針都一樣。
也就是說就算是指針同一個成員函數,但實例不同,委托就不同
為了方便使用,定義函數newDelegate來創建委托使用的函數
至此,對C++函數指針的封裝就完成了,不難吧。
下面就是委托的實現了
仔細理解下CMultiDelegate類的實現,代碼都不深奧。
比較重要的是3個函數 :+=,-=,()運算符的重載函數
+= 用於添加一個委托函數
-= 用於去掉一個委托函數
() 用於觸發委托函數
差不多就是普通的stl容器使用了。
這裡要重點說明的一點是,大家仔細看 += 函數的實現中
為什麼要delete掉外部的指針呢?
因為C++的內存洩露一直是個麻煩事,所以MyUGI的委托裡,所有的委托函數統一由Delegate本身管理
外部不要自己new或delete委托函數,也不要保存一個委托函數,Delegate本身會管理好的。
建議像如下使用:
而不建議像如下使用:
上面2種方法都沒錯,都不會造成內存洩露
你可能會覺得第2種方法減少new的次數,比第一種方法更好。其實不然,因為第2種方法有個很大的隱患
所以如果你後面又想將delegateFunc添加到myDelegate裡面時,你就不能再這樣用了
delegateFunc = newDelegate(normalFunc);
myDelegate += delegateFunc;
相信你不會願意這樣做的,因為這種方法很容易造成內存洩露或者崩潰
現在你應該可以明白 -= 函數是怎麼釋放委托函數內存了吧。
按上面的方法,你已經可以使用無參數的函數委托了。下一篇文章將會介紹如何實現任意參數的函數委托。