青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

兔子的技術(shù)博客

兔子

   :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
  202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

留言簿(10)

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

撰文:Don Clugston

翻譯:周翔

(接中篇)

委托(delegate

和成員函數(shù)指針不同,你不難發(fā)現(xiàn)委托的用處。最重要的,使用委托可以很容易地實(shí)現(xiàn)一個(gè)Subject/Observer設(shè)計(jì)模式的改進(jìn)版[GoF, p. 293]Observer(觀察者)模式顯然在GUI中有很多的應(yīng)用,但我發(fā)現(xiàn)它對(duì)應(yīng)用程序核心的設(shè)計(jì)也有很大的作用。委托也可用來(lái)實(shí)現(xiàn)策略(Strategy[GoF, p. 315]和狀態(tài)(State[GoF, p. 305]模式。

現(xiàn)在,我來(lái)說(shuō)明一個(gè)事實(shí),委托和成員函數(shù)指針相比并不僅僅是好用,而且比成員函數(shù)指針簡(jiǎn)單得多!既然所有的.NET語(yǔ)言都實(shí)現(xiàn)了委托,你可能會(huì)猜想如此高層的概念在匯編代碼中并不好實(shí)現(xiàn)。但事實(shí)并不是這樣:委托的實(shí)現(xiàn)確實(shí)是一個(gè)底層的概念,而且就像普通的函數(shù)調(diào)用一樣簡(jiǎn)單(并且很高效)。一個(gè)C++委托只需要包含一個(gè)this指針和一個(gè)簡(jiǎn)單的函數(shù)指針就夠了。當(dāng)你建立一個(gè)委托時(shí),你提供這個(gè)委托一個(gè)this指針,并向它指明需要調(diào)用哪一個(gè)函數(shù)。編譯器可以在建立委托時(shí)計(jì)算出調(diào)整this指針需要的偏移量。這樣在使用委托的時(shí)候,編譯器就什么事情都不用做了。這一點(diǎn)更好的是,編譯器可以在編譯時(shí)就可以完成全部這些工作,這樣的話,委托的處理對(duì)編譯器來(lái)說(shuō)可以說(shuō)是微不足道的工作了。在x86系統(tǒng)下將委托處理成的匯編代碼就應(yīng)該是這么簡(jiǎn)單:

mov ecx, [this]

call [pfunc]

但是,在標(biāo)準(zhǔn)C++中卻不能生成如此高效的代碼。 Borland為了解決委托的問(wèn)題在它的C++編譯器中加入了一個(gè)新的關(guān)鍵字(__closure,用來(lái)通過(guò)簡(jiǎn)潔的語(yǔ)法生成優(yōu)化的代碼。GNU編譯器也對(duì)語(yǔ)言進(jìn)行了擴(kuò)展,但和Borland的編譯器不兼容。如果你使用了這兩種語(yǔ)言擴(kuò)展中的一種,你就會(huì)限制自己只使用一個(gè)廠家的編譯器。而如果你仍然遵循標(biāo)準(zhǔn)C++的規(guī)則,你仍然可以實(shí)現(xiàn)委托,但實(shí)現(xiàn)的委托就不會(huì)是那么高效了。

有趣的是,C#和其他.NET語(yǔ)言中,執(zhí)行一個(gè)委托的時(shí)間要比一個(gè)函數(shù)調(diào)用慢8(參見http://msdn.microsoft.com/library/en-us/dndotnet/html/fastmanagedcode.asp)。我猜測(cè)這可能是垃圾收集和.NET安全檢查的需要。最近,微軟將“統(tǒng)一事件模型(unified event model)”加入到Visual C++中,隨著這個(gè)模型的加入,增加了__event __raise__hook__unhookevent_sourceevent_receiver等一些關(guān)鍵字。坦白地說(shuō),我對(duì)加入的這些特性很反感,因?yàn)檫@是完全不符合標(biāo)準(zhǔn)的,這些語(yǔ)法是丑陋的,因?yàn)樗鼈兪惯@種C++不像C++,并且會(huì)生成一堆執(zhí)行效率極低的代碼。

解決這個(gè)問(wèn)題的推動(dòng)力:對(duì)高效委托(fast delegate)的迫切需求

使用標(biāo)準(zhǔn)C++實(shí)現(xiàn)委托有一個(gè)過(guò)度臃腫的癥狀。大多數(shù)的實(shí)現(xiàn)方法使用的是同一種思路。這些方法的基本觀點(diǎn)是將成員函數(shù)指針看成委托��但這樣的指針只能被一個(gè)單獨(dú)的類使用。為了避免這種局限,你需要間接地使用另一種思路:你可以使用模版為每一個(gè)類建立一個(gè)“成員函數(shù)調(diào)用器(member function invoker)”。委托包含了this指針和一個(gè)指向調(diào)用器(invoker)的指針,并且需要在堆上為成員函數(shù)調(diào)用器分配空間。

對(duì)于這種方案已經(jīng)有很多種實(shí)現(xiàn),包括在CodeProject上的實(shí)現(xiàn)方案。各種實(shí)現(xiàn)在復(fù)雜性上、語(yǔ)法(比如,有的和C#的語(yǔ)法很接近)上、一般性上有所不同。最具權(quán)威的一個(gè)實(shí)現(xiàn)是boost::function。最近,它已經(jīng)被采用作為下一個(gè)發(fā)布的C++標(biāo)準(zhǔn)版本中的一部分[Sutter1]。希望它能夠被廣泛地使用。

就像傳統(tǒng)的委托實(shí)現(xiàn)方法一樣,我同樣發(fā)覺(jué)這種方法并不十分另人滿意。雖然它提供了大家所期望的功能,但是會(huì)混淆一個(gè)潛在的問(wèn)題:人們?nèi)狈?duì)一個(gè)語(yǔ)言的底層的構(gòu)造。 “成員函數(shù)調(diào)用器”的代碼對(duì)幾乎所有的類都是一樣的,在所有平臺(tái)上都出現(xiàn)這種情況是令人沮喪的。畢竟,堆被用上了。但在一些應(yīng)用場(chǎng)合下,這種新的方法仍然無(wú)法被接受。

我做的一個(gè)項(xiàng)目是離散事件模擬器,它的核心是一個(gè)事件調(diào)度程序,用來(lái)調(diào)用被模擬的對(duì)象的成員函數(shù)。大多數(shù)成員函數(shù)非常簡(jiǎn)單:它們只改變對(duì)象的內(nèi)部狀態(tài),有時(shí)在事件隊(duì)列(event queue)中添加將來(lái)要發(fā)生的事件,在這種情況下最適合使用委托。但是,每一個(gè)委托只被調(diào)用(invoked)一次。一開始,我使用了boost::function,但我發(fā)現(xiàn)程序運(yùn)行時(shí),給委托所分配的內(nèi)存空間占用了整個(gè)程序空間的三分之一還要多!“我要真正的委托!”我在內(nèi)心呼喊著,“真正的委托只需要僅僅兩行匯編指令啊!”

我并不能總是能夠得到我想要的,但后來(lái)我很幸運(yùn)。我在這兒展示的代碼(代碼下載鏈接見譯者注)幾乎在所有編譯環(huán)境中都產(chǎn)生了優(yōu)化的匯編代碼。最重要的是,調(diào)用一個(gè)含有單個(gè)目標(biāo)的委托(single-target delegate)的速度幾乎同調(diào)用一個(gè)普通函數(shù)一樣快。實(shí)現(xiàn)這樣的代碼并沒(méi)有用到什么高深的東西,唯一的遺憾就是,為了實(shí)現(xiàn)目標(biāo),我的代碼和標(biāo)準(zhǔn)C++的規(guī)則有些偏離。我使用了一些有關(guān)成員函數(shù)指針的未公開知識(shí)才使它能夠這樣工作。如果你很細(xì)心,而且不在意在少數(shù)情況下的一些編譯器相關(guān)(compiler-specific)的代碼,那么高性能的委托機(jī)制在任何C++編譯器下都是可行的。

訣竅:將任何類型的成員函數(shù)指針轉(zhuǎn)化為一個(gè)標(biāo)準(zhǔn)的形式

我的代碼的核心是一個(gè)能夠?qū)⑷魏晤惖闹羔樅腿魏纬蓡T函數(shù)指針?lè)謩e轉(zhuǎn)換為一個(gè)通用類的指針和一個(gè)通用成員函數(shù)的指針的類。由于C++沒(méi)有“通用成員函數(shù)(generic member function)”的類型,所以我把所有類型的成員函數(shù)都轉(zhuǎn)化為一個(gè)在代碼中未定義的CGenericClass類的成員函數(shù)。

大多數(shù)編譯器對(duì)所有的成員函數(shù)指針平等地對(duì)待,不管他們屬于哪個(gè)類。所以對(duì)這些編譯器來(lái)說(shuō),可以使用reinterpret_cast將一個(gè)特定的成員函數(shù)指針轉(zhuǎn)化為一個(gè)通用成員函數(shù)指針。事實(shí)上,假如編譯器不可以,那么這個(gè)編譯器是不符合標(biāo)準(zhǔn)的。對(duì)于一些接近標(biāo)準(zhǔn)(almost-compliant)的編譯器,比如Digital Mars,成員函數(shù)指針的reinterpret_cast轉(zhuǎn)換一般會(huì)涉及到一些額外的特殊代碼,當(dāng)進(jìn)行轉(zhuǎn)化的成員函數(shù)的類之間沒(méi)有任何關(guān)聯(lián)時(shí),編譯器會(huì)出錯(cuò)。對(duì)這些編譯器,我們使用一個(gè)名為horrible_cast的內(nèi)聯(lián)函數(shù)(在函數(shù)中使用了一個(gè)union來(lái)避免C++的類型檢查)。使用這種方法看來(lái)是不可避免的��boost::function也用到了這種方法。

對(duì)于其他的一些編譯器(如Visual C++, Intel C++Borland C++),我們必須將多重(multiple-)繼承和虛擬(virtual-)繼承類的成員函數(shù)指針轉(zhuǎn)化為單一(single-)繼承類的函數(shù)指針。為了實(shí)現(xiàn)這個(gè)目的,我巧妙地使用了模板并利用了一個(gè)奇妙的戲法。注意,這個(gè)戲法的使用是因?yàn)檫@些編譯器并不是完全符合標(biāo)準(zhǔn)的,但是使用這個(gè)戲法得到了回報(bào):它使這些編譯器產(chǎn)生了優(yōu)化的代碼。

既然我們知道編譯器是怎樣在內(nèi)部存儲(chǔ)成員函數(shù)指針的,并且我們知道在問(wèn)題中應(yīng)該怎樣為成員函數(shù)指針調(diào)整this指針,我們的代碼在設(shè)置委托時(shí)可以自己調(diào)整this指針。對(duì)單一繼承類的函數(shù)指針,則不需要進(jìn)行調(diào)整;對(duì)多重繼承,則只需要一次加法就可完成調(diào)整;對(duì)虛擬繼承...就有些麻煩了。但是這樣做是管用的,并且在大多數(shù)情況下,所有的工作都在編譯時(shí)完成!

這是最后一個(gè)訣竅。我們?cè)鯓訁^(qū)分不同的繼承類型?并沒(méi)有官方的方法來(lái)讓我們區(qū)分一個(gè)類是多重繼承的還是其他類型的繼承。但是有一種巧妙的方法,你可以查看我在前面給出了一個(gè)列表(見中篇)——對(duì)MSVC,每種繼承方式產(chǎn)生的成員函數(shù)指針的大小是不同的。所以,我們可以基于成員函數(shù)指針的大小使用模版!比如對(duì)多重繼承類型來(lái)說(shuō),這只是個(gè)簡(jiǎn)單的計(jì)算。而在確定unknown_inheritance16字節(jié))類型的時(shí)候,也會(huì)采用類似的計(jì)算方法。

對(duì)于微軟和英特爾的編譯器中采用不標(biāo)準(zhǔn)12字節(jié)的虛擬繼承類型的指針的情況,我引發(fā)了一個(gè)編譯時(shí)錯(cuò)誤(compile-time error),因?yàn)樾枰粋€(gè)特定的運(yùn)行環(huán)境(workaround)。如果你在MSVC中使用虛擬繼承,要在聲明類之前使用FASTDELEGATEDECLARE宏。而這個(gè)類必須使用unknown_inheritance(未知繼承類型)指針(這相當(dāng)于一個(gè)假定的__unknown_inheritance關(guān)鍵字)。例如:

FASTDELEGATEDECLARE(CDerivedClass)

class CDerivedClass : virtual public CBaseClass1, virtual public CBaseClass2 {

// : (etc)

};

這個(gè)宏和一些常數(shù)的聲明是在一個(gè)隱藏的命名空間中實(shí)現(xiàn)的,這樣在其他編譯器中使用時(shí)也是安全的。MSVC7.0或更新版本)的另一種方法是在工程中使用/vmg編譯器選項(xiàng)。而Inter的編譯器對(duì)/vmg編譯器選項(xiàng)不起作用,所以你必須在虛擬繼承類中使用宏。我的這個(gè)代碼是因?yàn)榫幾g器的bug才可以正確運(yùn)行,你可以查看代碼來(lái)了解更多細(xì)節(jié)。而在遵從標(biāo)準(zhǔn)的編譯器中不需要注意這么多,況且在任何情況下都不會(huì)妨礙FASTDELEGATEDECLARE宏的使用。

一旦你將類的對(duì)象指針和成員函數(shù)指針轉(zhuǎn)化為標(biāo)準(zhǔn)形式,實(shí)現(xiàn)單一目標(biāo)的委托(single-target delegate)就比較容易了(雖然做起來(lái)感覺(jué)冗長(zhǎng)乏味)。你只要為每一種具有不同參數(shù)的函數(shù)制作相應(yīng)的模板類就行了。實(shí)現(xiàn)其他類型的委托的代碼也大都與此相似,只是對(duì)參數(shù)稍做修改罷了。

這種用非標(biāo)準(zhǔn)方式轉(zhuǎn)換實(shí)現(xiàn)的委托還有一個(gè)好處,就是委托對(duì)象之間可以用等式比較。目前實(shí)現(xiàn)的大多數(shù)委托無(wú)法做到這一點(diǎn),這使這些委托不能勝任一些特定的任務(wù),比如實(shí)現(xiàn)多播委托(multi-cast delegates [Sutter3]

靜態(tài)函數(shù)作為委托目標(biāo)(delegate target

理論上,一個(gè)簡(jiǎn)單的非成員函數(shù)(non-member function),或者一個(gè)靜態(tài)成員函數(shù)(static member function)可以被作為委托目標(biāo)(delegate target)。這可以通過(guò)將靜態(tài)函數(shù)轉(zhuǎn)換為一個(gè)成員函數(shù)來(lái)實(shí)現(xiàn)。我有兩種方法實(shí)現(xiàn)這一點(diǎn),兩種方法都是通過(guò)使委托指向調(diào)用這個(gè)靜態(tài)函數(shù)的“調(diào)用器(invoker)”的成員函數(shù)的方法來(lái)實(shí)現(xiàn)的。

第一種方法使用了一個(gè)邪惡的方法(evil method)。你可以存儲(chǔ)函數(shù)指針而不是this指針,這樣當(dāng)調(diào)用“調(diào)用器”的函數(shù)時(shí),它將this指針轉(zhuǎn)化為一個(gè)靜態(tài)函數(shù)指針,并調(diào)用這個(gè)靜態(tài)函數(shù)。問(wèn)題是這只是一個(gè)戲法,它需要在代碼指針和數(shù)據(jù)指針之間進(jìn)行轉(zhuǎn)換。在一個(gè)系統(tǒng)中代碼指針的大小比數(shù)據(jù)指針大時(shí)(比如DOS下的編譯器使用medium內(nèi)存模式時(shí)),這個(gè)方法就不管用了。它在目前我知道的所有32位和64位處理器上是管用的。但是因?yàn)檫@種方法還是不太好,所以仍需要改進(jìn)。

另一種是一個(gè)比較安全的方法(safe method),它是將函數(shù)指針作為委托的一個(gè)附加成員。委托指向自己的成員函數(shù)。當(dāng)委托被復(fù)制的時(shí)候,這些自引用(self-reference)必須被轉(zhuǎn)換,而且使“=”和“==”運(yùn)算符的操作變得復(fù)雜。這使委托的大小增至4個(gè)字節(jié),并增加了代碼的復(fù)雜性,但這并不影響委托的調(diào)用速度。

我已經(jīng)實(shí)現(xiàn)了上述兩種方法,兩者都有各自的優(yōu)點(diǎn):安全的方法保證了運(yùn)行的可靠性,而邪惡的方法在支持委托的編譯器下也可能會(huì)產(chǎn)生與此相同的匯編代碼。此外,安全的方法可避免我以前討論的在MSVC中使用多重繼承和虛擬繼承時(shí)所出現(xiàn)的問(wèn)題。我在代碼中給出的是“安全的方法”的代碼,但是在我給出的代碼中“邪惡的方法”會(huì)通過(guò)下面的代碼生效:

#define (FASTDELEGATE_USESTATICFUNCTIONHACK)

多目標(biāo)委托(multiple-target delegate)及其擴(kuò)展

使用委托的人可能會(huì)想使委托調(diào)用多個(gè)目標(biāo)函數(shù),這就是多目標(biāo)委托(multiple-target delegate,也稱作多播委托(multi-cast delegate。實(shí)現(xiàn)這種委托不會(huì)降低單一目標(biāo)委托(single-target delegate)的調(diào)用效率,這在現(xiàn)實(shí)中是可行的。你只需要為一個(gè)委托的第二個(gè)目標(biāo)和后來(lái)的更多目標(biāo)在堆上分配空間就可以了,這意味著需要在委托類中添加一個(gè)數(shù)據(jù)指針,用來(lái)指向由該委托的目標(biāo)函數(shù)組成的單鏈表的頭部節(jié)點(diǎn)。如果委托只有一個(gè)目標(biāo)函數(shù),將這個(gè)目標(biāo)像以前介紹的方法一樣保存在委托中就行了。如果一個(gè)委托有多個(gè)目標(biāo)函數(shù),那么這些目標(biāo)都保存在空間動(dòng)態(tài)分配的鏈表中,如果要調(diào)用函數(shù),委托使用一個(gè)指針指向一個(gè)鏈表中的目標(biāo)(成員函數(shù)指針)。這樣的話,如果委托中只有一個(gè)目標(biāo),函數(shù)調(diào)用存儲(chǔ)單元的個(gè)數(shù)為1;如果有nn>0)個(gè)目標(biāo),則函數(shù)調(diào)用存儲(chǔ)單元的個(gè)數(shù)為n+1(因?yàn)檫@時(shí)函數(shù)指針保存在鏈表中,會(huì)多出一個(gè)鏈表頭,所以要再加一——譯者注),我認(rèn)為這樣做最合理。

由多播委托引出了一些問(wèn)題。怎樣處理返回值?(是將所有返回值類型捆綁在一起,還是忽略一部分?)如果把同一個(gè)目標(biāo)在一個(gè)委托中添加了兩次那會(huì)發(fā)生什么?(是調(diào)用同一個(gè)目標(biāo)兩次,還是只調(diào)用一次,還是作為一個(gè)錯(cuò)誤處理?)如果你想在委托中刪除一個(gè)不在其中的目標(biāo)應(yīng)該怎么辦?(是不管它,還是拋出一個(gè)異常?)

最重要的問(wèn)題是在使用委托時(shí)會(huì)出現(xiàn)無(wú)限循環(huán)的情況,比如,A委托調(diào)用一段代碼,而在這段代碼中調(diào)用B委托,而在B委托調(diào)用的一段代碼中又會(huì)調(diào)用A委托。很多事件(event)和信號(hào)跟蹤(signal-slot)系統(tǒng)會(huì)有一定的方案來(lái)處理這種問(wèn)題。

為了結(jié)束我的這篇文章,我的多播委托的實(shí)現(xiàn)方案就需要大家等待了。這可以借鑒其他實(shí)現(xiàn)中的方法——允許非空返回類型,允許類型的隱式轉(zhuǎn)換,并使用更簡(jiǎn)捷的語(yǔ)法結(jié)構(gòu)。如果我有足夠的興趣我會(huì)把代碼寫出來(lái)。如果能把我實(shí)現(xiàn)的委托和目前流行的某一個(gè)事件處理系統(tǒng)結(jié)合起來(lái)那會(huì)是最好不過(guò)的事情了(有自愿者嗎?)。

本文代碼的使用

原代碼包括了FastDelegate的實(shí)現(xiàn)(FastDelegate.h)和一個(gè)demo .cpp的文件用來(lái)展示使用FastDelegate的語(yǔ)法。對(duì)于使用MSVC的讀者,你可以建立一個(gè)空的控制臺(tái)應(yīng)用程序(Console Application)的工程,再把這兩個(gè)文件添加進(jìn)去就好了,對(duì)于GNU的使用者,在命令行輸入“gcc demo.cpp”就可以了。

FastDelegate可以在任何參數(shù)組合下運(yùn)行,我建議你在盡可能多的編譯器下嘗試,你在聲明委托的時(shí)候必須指明參數(shù)的個(gè)數(shù)。在這個(gè)程序中最多可以使用8個(gè)參數(shù),若想進(jìn)行擴(kuò)充也是很容易的。代碼使用了fastdelegate命名空間,在fastdelegate命名空間中有一個(gè)名為detail的內(nèi)部命名空間。

Fastdelegate使用構(gòu)造函數(shù)或bind()可以綁定一個(gè)成員函數(shù)或一個(gè)靜態(tài)(全局)函數(shù),在默認(rèn)情況下,綁定的值為0(空函數(shù))。可以使用“!”操作符判定它是一個(gè)空值。

不像用其他方法實(shí)現(xiàn)的委托,這個(gè)委托支持等式運(yùn)算符(==, !=)。

下面是FastDelegateDemo.cpp的節(jié)選,它展示了大多數(shù)允許的操作。CBaseClassCDerivedClass的虛基類。你可以根據(jù)這個(gè)代碼寫出更精彩的代碼,下面的代碼只是說(shuō)明使用FastDelegate的語(yǔ)法:

using namespace fastdelegate;

int main(void)

{

printf("-- FastDelegate demo --\nA no-parameter

delegate is declared using FastDelegate0\n\n");

FastDelegate0 noparameterdelegate(&SimpleVoidFunction);

noparameterdelegate();

//調(diào)用委托,這一句調(diào)用SimpleVoidFunction()

printf("\n-- Examples using two-parameter delegates (int, char *) --\n\n");

typedef FastDelegate2 MyDelegate;

MyDelegate funclist[12]; // 委托初始化,其目標(biāo)為空

CBaseClass a("Base A");

CBaseClass b("Base B");

CDerivedClass d;

CDerivedClass c;

// 綁定一個(gè)成員函數(shù)

funclist[0].bind(&a, &CBaseClass::SimpleMemberFunction);

//你也可以綁定一個(gè)靜態(tài)(全局)函數(shù)

funclist[1].bind(&SimpleStaticFunction);

//綁定靜態(tài)成員函數(shù)

funclist[2].bind(&CBaseClass::StaticMemberFunction);

// 綁定const型的成員函數(shù)

funclist[3].bind(&a, &CBaseClass::ConstMemberFunction);

// 綁定虛擬成員函數(shù)

funclist[4].bind(&b, &CBaseClass::SimpleVirtualFunction);

// 你可以使用”=”來(lái)賦值

funclist[5] = MyDelegate(&CBaseClass::StaticMemberFunction);

funclist[6].bind(&d, &CBaseClass::SimpleVirtualFunction);

//最麻煩的情況是綁定一個(gè)抽象虛擬函數(shù)(abstract virtual function

funclist[7].bind(&c, &CDerivedClass::SimpleDerivedFunction);

funclist[8].bind(&c, &COtherClass::TrickyVirtualFunction);

funclist[9] = MakeDelegate(&c, &CDerivedClass::SimpleDerivedFunction);

// 你也可以使用構(gòu)造函數(shù)來(lái)綁定

MyDelegate dg(&b, &CBaseClass::SimpleVirtualFunction);

char *msg = "Looking for equal delegate";

for (int i=0; i<12; i++) {

printf("%d :", i);

// 可以使用”==”

if (funclist[i]==dg) { msg = "Found equal delegate"; };

//可以使用”!”來(lái)判應(yīng)一個(gè)空委托

if (!funclist[i]) {

printf("Delegate is empty\n");

} else {

// 調(diào)用生成的經(jīng)過(guò)優(yōu)化的匯編代碼

funclist[i](i, msg);

};

}

};

因?yàn)槲业拇a利用了C++標(biāo)準(zhǔn)中沒(méi)有定義的行為,所以我很小心地在很多編譯器中做了測(cè)試。具有諷刺意味的是,它比許多所謂標(biāo)準(zhǔn)的代碼更具有可移植性,因?yàn)閹缀跛械木幾g器都不是完全符合標(biāo)準(zhǔn)的。目前,核心代碼已成功通過(guò)了下列編譯器的測(cè)試:

  • Microsoft Visual C++ 6.0, 7.0 (.NET) and 7.1 (.NET 2003) (including /clr 'managed C++'),

     

  • GNU G++ 3.2 (MingW binaries),

     

  • Borland C++ Builder 5.5.1,

     

  • Digital Mars C++ 8.38 (x86, both 32-bit and 16-bit),

     

  • Intel C++ for Windows 8.0,

     

  • Metroworks CodeWarrior for Windows 9.1 (in both C++ and EC++ modes)

     

對(duì)于Comeau C++ 4.3 (x86, SPARC, Alpha, Macintosh),能夠成功通過(guò)編譯,但不能鏈接和運(yùn)行。對(duì)于Intel C++ 8.0 for Itanium能夠成功通過(guò)編譯和鏈接,但不能運(yùn)行。

此外,我已對(duì)代碼在MSVC 1.5 4.0Open Watcom WCL 1.2上的運(yùn)行情況進(jìn)行了測(cè)試,由于這些編譯器不支持成員函數(shù)模版,所以對(duì)這些編譯器,代碼不能編譯成功。對(duì)于嵌入式系統(tǒng)不支持模版的限制,需要對(duì)代碼進(jìn)行大范圍的修改。(這一段是在剛剛更新的原文中添加的——譯者注)

而最終的FastDelegate并沒(méi)有進(jìn)行全面地測(cè)試,一個(gè)原因是,我有一些使用的編譯器的評(píng)估版過(guò)期了,另一個(gè)原因是——我的女兒出生了!如果有足夠的興趣,我會(huì)讓代碼在更多編譯器中通過(guò)測(cè)試。(這一段在剛剛更新的原文中被刪去了,因?yàn)樽髡吣壳皫缀跬瓿闪巳繙y(cè)試。——譯者注)

總結(jié)

為了解釋一小段代碼,我就得為這個(gè)語(yǔ)言中具有爭(zhēng)議的一部分寫這么一篇長(zhǎng)長(zhǎng)的指南。為了兩行匯編代碼,就要做如此麻煩的工作。唉~

我希望我已經(jīng)澄清了有關(guān)成員函數(shù)指針和委托的誤解。我們可以看到為了實(shí)現(xiàn)成員函數(shù)指針,各種編譯器有著千差萬(wàn)別的方法。我們還可以看到,與流行的觀點(diǎn)不同,委托并不復(fù)雜,并不是高層結(jié)構(gòu),事實(shí)上它很簡(jiǎn)單。我希望它能夠成為這個(gè)語(yǔ)言(標(biāo)準(zhǔn)C++)中的一部分,而且我們有理由相信目前已被一些編譯器支持的委托,在不久的將來(lái)會(huì)加入到標(biāo)準(zhǔn)C++的新的版本中(去游說(shuō)標(biāo)準(zhǔn)委員會(huì)!)。

據(jù)我所知,以前實(shí)現(xiàn)的委托都沒(méi)有像我在這里為大家展示的FastDelegate一樣有如此高的性能。我希望我的代碼能對(duì)你有幫助。如果我有足夠的興趣,我會(huì)對(duì)代碼進(jìn)行擴(kuò)展,從而支持多播委托(multi-cast delegate)以及更多類型的委托。我在CodeProject上學(xué)到了很多,并且這是我第一次為之做出的貢獻(xiàn)。

參考文獻(xiàn)

[GoF] "Design Patterns: Elements of Reusable Object-Oriented Software", E. Gamma, R. Helm, R. Johnson, and J. Vlissides.

I've looked at dozens of websites while researching this article. Here are a few of the most interesting ones:

我在寫這篇文章時(shí)查看了很多站點(diǎn),下面只是最有趣的一些站點(diǎn):

[Boost] Delegates can be implemented with a combination of boost::function and boost::bind. Boost::signals is one of the most sophisticated event/messaging system available. Most of the boost libraries require a highly standards-conforming compiler.http://www.boost.org/

[Loki] Loki provides 'functors' which are delegates with bindable parameters. They are very similar to boost::function. It's likely that Loki will eventually merge with boost. http://sourceforge.net/projects/loki-lib

[Qt] The Qt library includes a Signal/Slot mechanism (i.e., delegates). For this to work, you have to run a special preprocessor on your code before compiling. Performance is very poor, but it works on compilers with very poor template support.http://doc.trolltech.com/3.0/signalsandslots.html

[Libsigc++] An event system based on Qt's. It avoids the Qt's special preprocessor, but requires that every target be derived from a base object class (using virtual inheritance - yuck!). http://libsigc.sourceforge.net/

[Hickey]. An old (1994) delegate implementation that avoids memory allocations. Assumes that all pointer-to-member functions are the same size, so it doesn't work on MSVC. There's a helpful discussion of the code here. http://www.tutok.sk/fastgl/callback.html

[Haendal]. A website dedicated to function pointers?! Not much detail about member function pointers though.http://www.function-pointer.org/

[Sutter1] Generalized function pointers: a discussion of how boost::function has been accepted into the new C++ standard.http://www.cuj.com/documents/s=8464/cujcexp0308sutter/

[Sutter2] Generalizing the Observer pattern (essentially, multicast delegates) using std::tr1::function. Discusses the limitations of the failure of boost::function to provide operator ==.

http://www.cuj.com/documents/s=8840/cujexp0309sutter

[Sutter3] Herb Sutter's Guru of the Week article on generic callbacks. http://www.gotw.ca/gotw/083.htm

關(guān)于作者Don Clugston

我在澳大利亞的high-tech startup工作,是一個(gè)物理學(xué)家兼軟件工程師。目前從事將太陽(yáng)航空艙的硅質(zhì)晶體玻璃(CSG)薄膜向市場(chǎng)推廣的工作。我從事有關(guān)太陽(yáng)的(solar)研究,平時(shí)喜歡做一些軟件(用作數(shù)學(xué)模型、設(shè)備控制、離散事件觸發(fā)器和圖象處理等),我最近喜歡使用STLWTL寫代碼。我非常懷念過(guò)去的光榮歲月:)而最重要的,我有一個(gè)非常可愛(ài)的兒子(20025月出生)和一個(gè)非常年輕的小姐(20045月出生)。

“黑暗不會(huì)戰(zhàn)勝陽(yáng)光,陽(yáng)光終究會(huì)照亮黑暗。”

譯者注

由于本文剛發(fā)表不久,作者隨時(shí)都有可能對(duì)文章或代碼進(jìn)行更新,若要瀏覽作者對(duì)本文的最新內(nèi)容,請(qǐng)?jiān)L問(wèn):

http://www.codeproject.com/cpp/FastDelegate.asp

點(diǎn)擊以下鏈接下載FastDelegate的源代碼:

http://www.codeproject.com/cpp/FastDelegate/FastDelegate_src.zip

轉(zhuǎn)自:http://dev.csdn.net/htmls/30/30159.html


附文中提及 codeproject 文章中包含的源代碼:
Download source files:FastDelegate_src.zip 
Download macro files used to develop this library:FastDelegate_hopter.zip

posted on 2010-12-15 09:25 會(huì)飛的兔子 閱讀(420) 評(píng)論(0)  編輯 收藏 引用 所屬分類: C++及開發(fā)環(huán)境
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲午夜精品网| 亚洲欧美日韩国产综合精品二区| 在线成人性视频| 亚洲精品久久久一区二区三区| 午夜宅男欧美| 99在线热播精品免费| 老司机免费视频一区二区| 国产精品久久久久久久久久直播 | 国产精品99一区| 亚洲精品少妇| 欧美国产第一页| 久久精品视频在线看| 国产日产欧产精品推荐色| 亚洲免费一在线| 亚洲视频免费在线观看| 亚洲电影在线| 香蕉尹人综合在线观看| 国产精品免费小视频| 亚洲网站在线播放| 日韩午夜免费| 国产精品高清在线| 亚洲尤物视频网| 亚洲专区一二三| 国产在线不卡精品| 久久精品国产96久久久香蕉| 亚洲一区二区精品在线| 亚洲国内精品在线| 欧美激情欧美狂野欧美精品| 亚洲精品久久| 亚洲区一区二| 欧美三级网址| 欧美在线免费观看| 久久国产精品一区二区| 精品成人a区在线观看| 麻豆成人精品| 欧美激情在线有限公司| 亚洲性夜色噜噜噜7777| 亚洲午夜精品久久| 国产亚洲免费的视频看| 久久最新视频| 欧美日韩1区2区| 性色av一区二区三区| 久久av一区二区| 亚洲人成网站777色婷婷| 一区电影在线观看| 国产婷婷色一区二区三区在线 | 久久成人av少妇免费| 伊人久久婷婷| 99精品热视频| 国产一区二区丝袜高跟鞋图片| 女人天堂亚洲aⅴ在线观看| 欧美91大片| 香蕉尹人综合在线观看| 久久精品亚洲乱码伦伦中文| 亚洲美女区一区| 亚洲在线成人| 亚洲国产欧美日韩另类综合| 日韩亚洲一区二区| 国产在线欧美日韩| 亚洲毛片在线免费观看| 国产字幕视频一区二区| 亚洲人成精品久久久久| 国产视频亚洲| 99精品视频一区二区三区| 国产一区美女| 99在线精品免费视频九九视| 狠狠色丁香久久综合频道| 亚洲精品一区在线| 激情久久久久久久久久久久久久久久| 最新国产拍偷乱拍精品| 精品成人一区二区| 亚洲小说区图片区| 日韩视频在线观看免费| 欧美一区二区三区在线免费观看| 99在线视频精品| 老司机aⅴ在线精品导航| 欧美一区二区三区免费视| 欧美日韩岛国| 亚洲视频每日更新| 亚洲精品1区2区| 欧美一级久久| 亚洲自拍偷拍福利| 欧美精品久久一区二区| 久久天天躁夜夜躁狠狠躁2022 | 国产精品久久久久久久午夜片| 欧美 日韩 国产精品免费观看| 国产精品美女在线| 日韩视频永久免费| 亚洲精选久久| 欧美国产日本高清在线| 免费一区视频| 在线观看成人网| 久久人人九九| 巨乳诱惑日韩免费av| 国产一区二区三区四区老人| 亚洲综合精品自拍| 香蕉av777xxx色综合一区| 国产精品扒开腿做爽爽爽软件| 亚洲电影天堂av| 亚洲日本成人在线观看| 久热国产精品| 免费在线观看日韩欧美| 国产精品毛片| 亚洲女同精品视频| 欧美一区二区精品在线| 国产精品免费在线| 亚洲自拍都市欧美小说| 性欧美超级视频| 国产欧美在线观看| 欧美一区二区三区精品| 欧美在线综合视频| 国产视频一区在线观看一区免费| 午夜综合激情| 久久躁日日躁aaaaxxxx| 亚洲黄色尤物视频| 欧美国产大片| 亚洲少妇中出一区| 久久在线免费观看视频| 99一区二区| 国产香蕉久久精品综合网| 久久久久在线| 亚洲美女av在线播放| 欧美一级欧美一级在线播放| 黄色精品一区| 欧美激情网友自拍| 亚洲一区观看| 欧美激情亚洲自拍| 香蕉亚洲视频| 日韩午夜av| 亚洲欧洲日产国产网站| 国产精品99久久久久久有的能看 | 亚洲精品国产无天堂网2021| 欧美视频福利| 久久九九99视频| 日韩一区二区精品在线观看| 欧美在线观看日本一区| 在线观看日韩欧美| 欧美日韩国语| 欧美在线关看| 91久久精品国产91久久性色tv| 日韩视频一区| 国产乱码精品一区二区三区av| 欧美一区二区三区在线看| 欧美大片在线观看| 欧美在线观看一区二区| 日韩一二三在线视频播| 亚洲欧洲精品一区二区三区波多野1战4 | 欧美中在线观看| 亚洲国产日韩欧美综合久久| 99精品视频免费在线观看| 欧美激情亚洲激情| 亚洲永久免费精品| 你懂的国产精品| 久久久青草婷婷精品综合日韩| 亚洲第一区中文99精品| 欧美区一区二| 久久精品国产第一区二区三区最新章节 | 国产综合视频| 欧美韩国在线| 欧美jjzz| 亚洲欧美在线一区| 欧美激情一区在线观看| 亚洲欧美国产日韩中文字幕| aaa亚洲精品一二三区| 国产伦精品一区| 欧美二区视频| 欧美在线日韩精品| 羞羞答答国产精品www一本| 制服丝袜激情欧洲亚洲| 国产亚洲精品自拍| 欧美精品在欧美一区二区少妇| 亚洲欧美日韩另类精品一区二区三区| 999在线观看精品免费不卡网站| 久久久91精品国产一区二区精品| 亚洲欧洲视频| 好吊视频一区二区三区四区| 久久精品99国产精品酒店日本| 亚洲午夜av| 亚洲电影专区| 国产亚洲aⅴaaaaaa毛片| 欧美色道久久88综合亚洲精品| 欧美日韩日本国产亚洲在线| 久久免费精品日本久久中文字幕| 国产精品99久久99久久久二8| 欧美国内亚洲| 亚洲一级片在线观看| 亚洲一区二区影院| 亚洲精品中文字幕在线| 在线观看一区视频| 国产色视频一区| 国产一区深夜福利| 国产精品一区免费在线观看| 欧美揉bbbbb揉bbbbb| 欧美激情第五页| 午夜免费在线观看精品视频| 亚洲夜间福利| 亚洲视频1区2区| 欧美成人嫩草网站| 女主播福利一区| 欧美国产视频日韩|