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

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 閱讀(489) 評論(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>
            欧美日韩妖精视频| 亚洲三级性片| 国产一区二区三区的电影| 欧美午夜在线视频| 欧美视频在线免费看| 欧美日韩国产一中文字不卡| 欧美激情在线| 欧美天天视频| 国产日韩专区| 在线观看欧美激情| 亚洲大胆女人| 一本一本大道香蕉久在线精品| 宅男在线国产精品| 亚洲欧美中文日韩在线| 欧美在线视频观看| 麻豆精品一区二区综合av| 欧美激情一区二区三区蜜桃视频| 亚洲人成绝费网站色www| 宅男噜噜噜66一区二区| 久久er99精品| 欧美大片免费看| 国产精品五月天| 亚洲国产综合在线| 午夜欧美理论片| 欧美成人嫩草网站| 亚洲午夜影视影院在线观看| 久久久久久久综合狠狠综合| 欧美日韩亚洲综合| 一本色道久久99精品综合| 国产精品videossex久久发布| 欧美日韩久久精品| 国产亚洲欧美一级| av成人动漫| 久久免费视频观看| 99精品久久| 久久综合国产精品| 国产精品a级| 亚洲电影免费观看高清完整版| 亚洲网站在线播放| 欧美大片91| 欧美在线视频日韩| 国产精品久久久久999| 亚洲片国产一区一级在线观看| 亚洲欧美日韩电影| 亚洲欧洲日本mm| 久久久久久久一区二区三区| 国产精品亚洲美女av网站| 亚洲剧情一区二区| 农村妇女精品| 久久国产精品黑丝| 国产精品日韩精品| 亚洲一区三区视频在线观看| 亚洲国内高清视频| 欧美 日韩 国产 一区| 尤物在线观看一区| 久久精品国产999大香线蕉| 一本色道久久加勒比88综合| 欧美激情亚洲一区| 亚洲人成网站在线观看播放| 免费观看30秒视频久久| 久久精品视频在线播放| 国产午夜精品全部视频播放 | 亚洲无限av看| 亚洲精品免费看| 欧美激情2020午夜免费观看| 亚洲精品免费电影| 亚洲欧洲在线一区| 欧美精选在线| 亚洲一区二区在线看| 亚洲少妇一区| 国产日韩高清一区二区三区在线| 午夜视频一区| 欧美资源在线观看| 亚洲国产成人在线| 亚洲人精品午夜| 欧美天堂亚洲电影院在线观看| 亚洲综合色噜噜狠狠| 亚洲欧美日韩国产一区二区三区| 国产日本精品| 欧美freesex8一10精品| 欧美1区2区视频| 99re热精品| 在线中文字幕日韩| 国内一区二区三区在线视频| 牛夜精品久久久久久久99黑人 | 亚洲国产导航| 欧美激情中文字幕乱码免费| 亚洲精品影视| 亚洲图片欧美午夜| 韩日欧美一区二区| 亚洲国产日韩一区二区| 国产精品成人观看视频免费| 久久高清福利视频| 老色鬼久久亚洲一区二区| 99视频热这里只有精品免费| 亚洲午夜精品久久久久久浪潮| 国产亚洲欧美一区| 亚洲国产精品成人综合| 国产精品入口麻豆原神| 欧美电影免费观看高清完整版| 欧美日韩国产成人在线观看| 久久精品成人欧美大片古装| 男人的天堂成人在线| 欧美亚洲系列| 欧美激情 亚洲a∨综合| 久久蜜桃资源一区二区老牛 | 老色批av在线精品| 午夜一区在线| 欧美激情四色| 另类激情亚洲| 国产精品推荐精品| 亚洲美女色禁图| 亚洲电影欧美电影有声小说| 亚洲男人第一av网站| 日韩一区二区免费看| 久久久亚洲人| 久久九九国产精品怡红院| 欧美日韩一区在线播放| 亚洲成在线观看| 好看的亚洲午夜视频在线| 亚洲影院高清在线| 一区二区三区成人| 欧美成人精品h版在线观看| 久久久久国产精品一区| 国产精品嫩草99av在线| 亚洲精品美女91| 亚洲看片网站| 欧美肥婆bbw| 欧美成人一二三| 伊人精品视频| 久久久999成人| 久久免费99精品久久久久久| 国产美女诱惑一区二区| 亚洲一区二区三区色| 亚洲一区二区综合| 欧美午夜不卡影院在线观看完整版免费| 欧美成人资源| 亚洲日韩成人| 欧美激情一区二区三区在线| 亚洲黄网站黄| 99亚洲精品| 欧美婷婷在线| 亚洲婷婷国产精品电影人久久| 中文国产成人精品| 欧美日韩一区二区三区免费| 亚洲精品自在久久| 国产欧美日韩91| 国产精品分类| 99精品欧美一区二区三区| 中国成人在线视频| 欧美色精品在线视频| 一区二区三区四区五区精品| 亚洲男女毛片无遮挡| 国产免费成人| 久久视频在线视频| 亚洲韩国青草视频| 一本色道久久综合精品竹菊| 欧美日韩成人综合| 亚洲一区bb| 久久琪琪电影院| 亚洲日本va午夜在线影院| 欧美阿v一级看视频| 日韩亚洲欧美一区二区三区| 午夜精品影院在线观看| 国产综合香蕉五月婷在线| 欧美成人r级一区二区三区| 亚洲精品久久久蜜桃| 午夜精品久久久久久久久| 狠狠综合久久| 欧美日韩国产va另类| 亚洲欧美制服中文字幕| 欧美不卡在线| 亚洲综合另类| 亚洲国产婷婷香蕉久久久久久| 欧美日韩亚洲系列| 久久精品国产77777蜜臀| 亚洲精品精选| 久久夜色精品国产欧美乱| 一区二区免费看| 激情综合色丁香一区二区| 欧美日韩亚洲一区二区三区在线观看 | 久久五月激情| 一区二区激情| 欧美凹凸一区二区三区视频| 亚洲欧美日韩一区| 伊人久久大香线蕉综合热线| 欧美日韩一区二区三区免费看| 久久精品国产亚洲a| 一区二区不卡在线视频 午夜欧美不卡在| 久久偷看各类wc女厕嘘嘘偷窃| av成人免费在线观看| 国产在线观看一区| 国产精品成人一区二区三区吃奶| 久热精品在线视频| 亚洲欧美伊人| 一本久久a久久免费精品不卡| 欧美国产日韩一区二区| 久久久综合网站| 欧美一区网站| 亚洲女人小视频在线观看|