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

We do not always find visible happiness in proportion to visible virtue

夢幻白樺林

SHARE

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  14 Posts :: 58 Stories :: 62 Comments :: 0 Trackbacks

公告

常用鏈接

留言簿(5)

搜索

  •  

最新隨筆

最新評論

閱讀排行榜

委托(delegate)
  
  和成員函數指針不同,你不難發現委托的用處。最重要的,使用委托可以很容易地實現一個 Subject/Observer設計模式的改進版[GoF, p. 293]。Observer(觀察者)模式顯然在GUI中有很多的應用,但我發現它對應用程序核心的設計也有很大的作用。委托也可用來實現策略(Strategy)[GoF, p. 315]和狀態(State)[GoF, p. 305]模式。
  
  現在,我來說明一個事實,委托和成員函數指針相比并不僅僅是好用,而且比成員函數指針簡單得多!既然所有的.NET語言都實現了委托,你可能會猜想如此高層的概念在匯編代碼中并不好實現。但事實并不是這樣:委托的實現確實是一個底層的概念,而且就像普通的函數調用一樣簡單(并且很高效)。一個C++委托只需要包含一個this 指針和一個簡單的函數指針就夠了。當你建立一個委托時,你提供這個委托一個this指針,并向它指明需要調用哪一個函數。編譯器可以在建立委托時計算出調整this指針需要的偏移量。這樣在使用委托的時候,編譯器就什么事情都不用做了。這一點更好的是,編譯器可以在編譯時就可以完成全部這些工作,這樣的話,委托的處理對編譯器來說可以說是微不足道的工作了。在x86系統下將委托處理成的匯編代碼就應該是這么簡單:
  
  mov ecx, [this]
  
  call [pfunc]
  
  但是,在標準C++中卻不能生成如此高效的代碼。 Borland為了解決委托的問題在它的C++編譯器中加入了一個新的關鍵字(__closure),用來通過簡潔的語法生成優化的代碼。GNU編譯器也對語言進行了擴展,但和Borland的編譯器不兼容。如果你使用了這兩種語言擴展中的一種,你就會限制自己只使用一個廠家的編譯器。而如果你仍然遵循標準C++的規則,你仍然可以實現委托,但實現的委托就不會是那么高效了。
  
  有趣的是,在C#和其他.NET語言中,執行一個委托的時間要比一個函數調用慢8倍(參見http://msdn.microsoft.com/library/en- us/dndotnet/html/fastmanagedcode.asp)。我猜測這可能是垃圾收集和.NET安全檢查的需要。最近,微軟將“統一事件模型(unified event model)”加入到Visual C++中,隨著這個模型的加入,增加了__event、 __raise、__hook、__unhook、event_source和event_receiver等一些關鍵字。坦白地說,我對加入的這些特性很反感,因為這是完全不符合標準的,這些語法是丑陋的,因為它們使這種C++不像C++,并且會生成一堆執行效率極低的代碼。
  
  解決這個問題的推動力:對高效委托(fast delegate)的迫切需求
  
  使用標準C++實現委托有一個過度臃腫的癥狀。大多數的實現方法使用的是同一種思路。這些方法的基本觀點是將成員函數指針看成委托??但這樣的指針只能被一個單獨的類使用。為了避免這種局限,你需要間接地使用另一種思路:你可以使用模版為每一個類建立一個“成員函數調用器(member function invoker)”。委托包含了this指針和一個指向調用器(invoker)的指針,并且需要在堆上為成員函數調用器分配空間。
  
  對于這種方案已經有很多種實現,包括在CodeProject上的實現方案。各種實現在復雜性上、語法(比如,有的和C#的語法很接近)上、一般性上有所不同。最具權威的一個實現是boost::function。最近,它已經被采用作為下一個發布的C++標準版本中的一部分[Sutter1]。希望它能夠被廣泛地使用。
  
  就像傳統的委托實現方法一樣,我同樣發覺這種方法并不十分另人滿意。雖然它提供了大家所期望的功能,但是會混淆一個潛在的問題:人們缺乏對一個語言的底層的構造。 “成員函數調用器”的代碼對幾乎所有的類都是一樣的,在所有平臺上都出現這種情況是令人沮喪的。畢竟,堆被用上了。但在一些應用場合下,這種新的方法仍然無法被接受。
  
  我做的一個項目是離散事件模擬器,它的核心是一個事件調度程序,用來調用被模擬的對象的成員函數。大多數成員函數非常簡單:它們只改變對象的內部狀態,有時在事件隊列(event queue)中添加將來要發生的事件,在這種情況下最適合使用委托。但是,每一個委托只被調用(invoked)一次。一開始,我使用了boost:: function,但我發現程序運行時,給委托所分配的內存空間占用了整個程序空間的三分之一還要多!“我要真正的委托!”我在內心呼喊著,“真正的委托只需要僅僅兩行匯編指令啊!”
  
  我并不能總是能夠得到我想要的,但后來我很幸運。我在這兒展示的代碼(代碼下載鏈接見譯者注)幾乎在所有編譯環境中都產生了優化的匯編代碼。最重要的是,調用一個含有單個目標的委托(single-target delegate)的速度幾乎同調用一個普通函數一樣快。實現這樣的代碼并沒有用到什么高深的東西,唯一的遺憾就是,為了實現目標,我的代碼和標準C++ 的規則有些偏離。我使用了一些有關成員函數指針的未公開知識才使它能夠這樣工作。如果你很細心,而且不在意在少數情況下的一些編譯器相關(compiler-specific)的代碼,那么高性能的委托機制在任何C++編譯器下都是可行的。
  
  訣竅:將任何類型的成員函數指針轉化為一個標準的形式
  
  我的代碼的核心是一個能夠將任何類的指針和任何成員函數指針分別轉換為一個通用類的指針和一個通用成員函數的指針的類。由于C++沒有“通用成員函數(geneic member function)”的類型,所以我把所有類型的成員函數都轉化為一個在代碼中未定義的CGenericClass類的成員函數。
  
  大多數編譯器對所有的成員函數指針平等地對待,不管他們屬于哪個類。所以對這些編譯器來說,可以使用reinterpret_cast將一個特定的成員函數指針轉化為一個通用成員函數指針。事實上,假如編譯器不可以,那么這個編譯器是不符合標準的。對于一些接近標準(almost-compliant)的編譯器,比如Digital Mars,成員函數指針的reinterpret_cast轉換一般會涉及到一些額外的特殊代碼,當進行轉化的成員函數的類之間沒有任何關聯時,編譯器會出錯。對這些編譯器,我們使用一個名為horrible_cast的內聯函數(在函數中使用了一個union來避免C++的類型檢查)。使用這種方法看來是不可避免的??boost::function也用到了這種方法。
  
  對于其他的一些編譯器(如Visual C++, Intel C++和Borland C++),我們必須將多重(multiple-)繼承和虛擬(virtual-)繼承類的成員函數指針轉化為單一(single-)繼承類的函數指針。為了實現這個目的,我巧妙地使用了模板并利用了一個奇妙的戲法。注意,這個戲法的使用是因為這些編譯器并不是完全符合標準的,但是使用這個戲法得到了回報:它使這些編譯器產生了優化的代碼。
  
  既然我們知道編譯器是怎樣在內部存儲成員函數指針的,并且我們知道在問題中應該怎樣為成員函數指針調整this指針,我們的代碼在設置委托時可以自己調整this指針。對單一繼承類的函數指針,則不需要進行調整;對多重繼承,則只需要一次加法就可完成調整;對虛擬繼承...就有些麻煩了。但是這樣做是管用的,并且在大多數情況下,所有的工作都在編譯時完成!
  
  這是最后一個訣竅。我們怎樣區分不同的繼承類型?并沒有官方的方法來讓我們區分一個類是多重繼承的還是其他類型的繼承。但是有一種巧妙的方法,你可以查看我在前面給出了一個列表(見中篇)——對MSVC,每種繼承方式產生的成員函數指針的大小是不同的。所以,我們可以基于成員函數指針的大小使用模版!比如對多重繼承類型來說,這只是個簡單的計算。而在確定unknown_inheritance(16字節)類型的時候,也會采用類似的計算方法。
  
  對于微軟和英特爾的編譯器中采用不標準12字節的虛擬繼承類型的指針的情況,我引發了一個編譯時錯誤(compile-time error),因為需要一個特定的運行環境(workaround)。如果你在MSVC中使用虛擬繼承,要在聲明類之前使用 FASTDELEGATEDECLARE宏。而這個類必須使用unknown_inheritance(未知繼承類型)指針(這相當于一個假定的 __unknown_inheritance關鍵字)。例如:
  
FASTDELEGATEDECLARE(CDerivedClass)
  
  
class CDerivedClass : virtual public CBaseClass1, virtual public CBaseClass2 {
  
  
// : (etc)
  
  };

  
  這個宏和一些常數的聲明是在一個隱藏的命名空間中實現的,這樣在其他編譯器中使用時也是安全的。MSVC(7.0或更新版本)的另一種方法是在工程中使用/vmg編譯器選項。而Inter的編譯器對/vmg編譯器選項不起作用,所以你必須在虛擬繼承類中使用宏。我的這個代碼是因為編譯器的bug才可以正確運行,你可以查看代碼來了解更多細節。而在遵從標準的編譯器中不需要注意這么多,況且在任何情況下都不會妨礙FASTDELEGATEDECLARE宏的使用。
  
  一旦你將類的對象指針和成員函數指針轉化為標準形式,實現單一目標的委托(single-target delegate)就比較容易了(雖然做起來感覺冗長乏味)。你只要為每一種具有不同參數的函數制作相應的模板類就行了。實現其他類型的委托的代碼也大都與此相似,只是對參數稍做修改罷了。
  
  這種用非標準方式轉換實現的委托還有一個好處,就是委托對象之間可以用等式比較。目前實現的大多數委托無法做到這一點,這使這些委托不能勝任一些特定的任務,比如實現多播委托(multi-cast delegates) [Sutter3]。
  
  靜態函數作為委托目標(delegate target)
  
  理論上,一個簡單的非成員函數(non-member function),或者一個靜態成員函數(static member function)可以被作為委托目標(delegate target)。這可以通過將靜態函數轉換為一個成員函數來實現。我有兩種方法實現這一點,兩種方法都是通過使委托指向調用這個靜態函數的“調用器(invoker)”的成員函數的方法來實現的。
posted on 2007-06-08 00:18 colys 閱讀(487) 評論(0)  編輯 收藏 引用 所屬分類: C++

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美一区二区三区在线免费观看| 亚洲欧美日韩视频二区| 免费成人毛片| 亚洲国产美女精品久久久久∴| 老司机免费视频一区二区三区 | 国产精品综合色区在线观看| 亚洲在线观看视频网站| 亚洲性视频h| 国产亚洲精品v| 国产在线成人| 欧美大片一区二区三区| 欧美精品二区| 亚洲免费一在线| 欧美中在线观看| 亚洲激情一区二区三区| 99在线|亚洲一区二区| 国产精品久久久久久久久动漫| 午夜国产精品视频| 久久久久99精品国产片| 亚洲乱码国产乱码精品精| 一区二区三区久久精品| 极品av少妇一区二区| 91久久黄色| 免费中文字幕日韩欧美| 亚洲欧美视频一区二区三区| 久久只精品国产| 亚洲一区二区三区精品视频| 欧美一区二区视频免费观看| 日韩亚洲欧美一区| 欧美一区精品| 亚洲无人区一区| 久久综合影视| 午夜亚洲一区| 久久综合久久综合久久| 亚洲一区二区三区四区在线观看 | 欧美一激情一区二区三区| 亚洲国产视频一区| 亚洲欧美综合| 99国产一区| 麻豆精品视频在线| 亚洲综合视频一区| 欧美福利视频在线| 久久在线免费观看| 国产欧美日韩一区| 亚洲美女福利视频网站| 在线播放视频一区| 午夜在线视频一区二区区别| 亚洲午夜女主播在线直播| 久久久久综合| 久久精品国产在热久久 | 亚洲综合精品自拍| 一本色道88久久加勒比精品| 久久综合九色九九| 久久伊人免费视频| 国产精品久久久久久亚洲调教| 欧美激情一区三区| 亚洲欧洲日本国产| 免费久久久一本精品久久区| 免费看亚洲片| 在线观看日韩av电影| 久久se精品一区二区| 欧美有码在线观看视频| 国产精品夜色7777狼人| 一区二区三区黄色| 亚洲自拍高清| 国产精品美女久久久浪潮软件| 亚洲视频综合在线| 可以看av的网站久久看| 最新亚洲激情| 亚洲一区二区在线看| 亚洲精品之草原avav久久| 欧美va天堂| 亚洲国产专区校园欧美| 亚洲精品国产欧美| 欧美成人tv| 99成人免费视频| 午夜久久久久久| 国产午夜亚洲精品羞羞网站| 亚洲欧美日韩在线不卡| 久久久久久免费| 激情视频一区| 米奇777在线欧美播放| 亚洲国产精品一区制服丝袜| 亚洲伦理在线免费看| 免费在线播放第一区高清av| 亚洲国产一区二区三区高清| 亚洲美女色禁图| 欧美无砖砖区免费| 欧美制服第一页| 欧美激情麻豆| 午夜精彩国产免费不卡不顿大片| 国产日产精品一区二区三区四区的观看方式 | 亚洲少妇中出一区| 国产女主播视频一区二区| 久久精品青青大伊人av| 亚洲国产精品一区二区三区| 制服丝袜激情欧洲亚洲| 国产亚洲在线| 欧美激情网站在线观看| 亚洲欧美99| 亚洲国产成人在线| 亚洲欧美精品一区| 亚洲国产欧美一区| 国产精品毛片大码女人| 玖玖视频精品| 亚洲男人的天堂在线观看| 免费观看成人www动漫视频| 99精品国产高清一区二区| 国产色视频一区| 欧美日韩国产另类不卡| 久久久国产精品一区二区三区| 亚洲人在线视频| 欧美一区中文字幕| 中文国产成人精品久久一| 国产伊人精品| 欧美天天在线| 欧美激情免费在线| 久久电影一区| 亚洲午夜日本在线观看| 亚洲黄色成人网| 玖玖玖免费嫩草在线影院一区| 亚洲永久免费精品| 亚洲人www| 国产亚洲精品aa| 欧美日韩你懂的| 久久久水蜜桃av免费网站| 亚洲欧美日韩国产综合在线| 欧美激情视频给我| 久热国产精品| 久久久久国产精品麻豆ai换脸| 欧美在线高清视频| 亚洲国产专区校园欧美| 欧美视频国产精品| 欧美大片91| 久色成人在线| 久久亚洲综合色| 久久婷婷综合激情| 久久久久久久综合| 久久国内精品视频| 亚洲欧美日韩精品一区二区| 一区二区三区四区精品| 一区二区三区高清在线| 在线一区二区三区做爰视频网站| 亚洲看片一区| 99热免费精品| 亚洲美女中文字幕| 亚洲精品精选| 夜夜嗨av一区二区三区网站四季av| 亚洲国产日本| 亚洲国产一区二区三区a毛片| 亚洲二区在线视频| 亚洲精品一区在线观看| 亚洲精品自在久久| 亚洲天堂成人在线观看| 亚洲一区二区在线视频| 欧美亚洲在线观看| 久久久av水蜜桃| 欧美成人性生活| 欧美日韩在线播放三区四区| 国产精品美女视频网站| 亚洲欧美国产不卡| 国产午夜精品福利| 在线欧美视频| 在线亚洲欧美| 欧美主播一区二区三区| 久久大逼视频| 欧美激情网站在线观看| 亚洲精品国产拍免费91在线| 亚洲免费观看在线视频| 亚洲制服少妇| 久久伊人一区二区| 欧美久久久久免费| 国产日韩精品一区二区| 亚洲国产一区二区精品专区| 在线亚洲免费视频| 久久全国免费视频| 亚洲欧洲综合| 性高湖久久久久久久久| 免费91麻豆精品国产自产在线观看| 欧美激情在线狂野欧美精品| 国产精品推荐精品| 亚洲国产免费| 久久精品国产一区二区三区免费看 | 久久精品久久99精品久久| 亚洲夫妻自拍| 性欧美8khd高清极品| 欧美伦理视频网站| 国产亚洲欧美激情| 中文精品视频| 欧美黑人多人双交| 99国内精品久久| 美日韩精品免费| 国产精品va在线| 亚洲欧洲日产国码二区| 久久精品99久久香蕉国产色戒| 亚洲精品美女久久久久| 午夜精品久久久久| 国产精品盗摄久久久| 亚洲靠逼com| 欧美风情在线观看|