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

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>
            亚洲久久一区二区| 欧美亚洲视频一区二区| 亚洲视频在线一区观看| 亚洲国产成人精品久久久国产成人一区| 欧美日韩成人在线观看| 欧美电影免费| 欧美视频一区二区三区…| 国产精品av免费在线观看| 欧美性生交xxxxx久久久| 欧美私人网站| 国产日韩久久| 亚洲欧洲精品一区| 亚洲一区二区精品在线| 欧美一区二区三区免费大片| 欧美v亚洲v综合ⅴ国产v| 亚洲激情啪啪| 欧美一区二区啪啪| 欧美不卡在线视频| 欧美激情国产精品| 国产视频亚洲| 亚洲淫片在线视频| 欧美搞黄网站| 亚洲欧美日本国产有色| 欧美好骚综合网| 国内精品伊人久久久久av一坑| 亚洲国产日韩在线一区模特| 亚洲一区二区三区在线观看视频 | 在线观看精品| 久久精品国产精品亚洲| 艳女tv在线观看国产一区| 亚洲欧美日韩专区| 国产精品久久久久毛片软件| 制服丝袜激情欧洲亚洲| 亚洲激情视频网站| 欧美另类久久久品| 亚洲精品韩国| 亚洲人成网在线播放| 欧美精品一区二区在线观看 | 国产亚洲欧美日韩日本| 性欧美8khd高清极品| 亚洲综合视频一区| 国产亚洲精品aa| 亚洲大片av| 欧美日韩中文在线观看| 欧美在线观看一区| 久久在线观看视频| 日韩视频在线免费观看| 欧美.www| 亚洲美女在线国产| 亚洲精选中文字幕| 欧美日韩伊人| 久久久噜噜噜久久狠狠50岁| 久久婷婷综合激情| 亚洲欧美日韩国产| 久久精品人人做人人爽| 亚洲黄网站在线观看| 亚洲每日在线| 国内自拍亚洲| 亚洲午夜激情网站| 一区在线播放视频| 欧美色图天堂网| 黄色精品免费| 亚洲美洲欧洲综合国产一区| 国产日产欧产精品推荐色 | 夜夜精品视频| 黄色亚洲精品| 亚洲欧美日韩另类精品一区二区三区| 国产一区二区三区在线观看精品| 久久久999国产| 另类酷文…触手系列精品集v1小说| 欧美精品一区二区高清在线观看| 激情91久久| 欧美成人官网二区| 国产精品自在在线| 久久久综合视频| 欧美成人网在线| 欧美在线日韩在线| 免费在线国产精品| 久久久久.com| 欧美黄免费看| 麻豆精品视频在线| 国产精品手机在线| 美女黄网久久| 国产精品成人免费| 91久久精品网| 亚洲国产精品成人精品| 欧美在线免费| 欧美一区日韩一区| 乱中年女人伦av一区二区| 欧美亚洲日本国产| 国产一区二区三区四区在线观看| 亚洲国产1区| 国产日韩欧美综合精品| 欧美一区二区成人| 蜜臀99久久精品久久久久久软件 | 久久天天躁狠狠躁夜夜av| 亚洲夜晚福利在线观看| 欧美va天堂| 一区二区三区国产在线| 午夜精品久久久久久久久久久久| 欧美人交a欧美精品| 最新中文字幕一区二区三区| 亚洲三级电影全部在线观看高清| 老司机午夜精品视频| 日韩一区二区免费看| 亚洲欧美美女| 国内揄拍国内精品久久| 媚黑女一区二区| 一区二区三区四区五区精品视频| 99国产精品99久久久久久| 国产麻豆视频精品| 久久综合九九| 久久一日本道色综合久久| 亚洲视频高清| 这里只有精品电影| 久久免费视频一区| 亚洲一区二区久久| 久久只有精品| 欧美专区在线播放| 亚洲精品日韩精品| 久久一区二区三区av| 亚洲伊人伊色伊影伊综合网| 一区二区三区在线视频观看| 国产精品视频999| 免费91麻豆精品国产自产在线观看| 久久精品欧美日韩| 在线观看一区视频| 欧美高清视频在线观看| 欧美gay视频| 亚洲成人在线网站| 欧美高清视频在线播放| 免费成人激情视频| 久久久久一区二区| 久久黄色小说| aa亚洲婷婷| 欧美日韩精品一区| 国产精品白丝jk黑袜喷水| 久久午夜av| 久久久久国内| 免费在线国产精品| 国产精品一区在线观看你懂的| 欧美成人激情视频| 欧美大片va欧美在线播放| 国产精品女主播| 国产一区二区丝袜高跟鞋图片| 娇妻被交换粗又大又硬视频欧美| 欧美日韩在线视频观看| 免费在线视频一区| 国产精品不卡在线| 国产欧美日韩| 亚洲美洲欧洲综合国产一区| 中文欧美字幕免费| 久热精品视频在线观看一区| 亚洲国产精品黑人久久久| 99国产精品久久久久久久| 亚洲午夜精品一区二区| 黄色成人小视频| 欧美1区3d| 国产一区二区在线观看免费| 正在播放亚洲| 亚洲福利av| 久久激情视频| 激情综合在线| 久久免费高清| 久久精品99国产精品| 99riav久久精品riav| 欧美日韩精品综合在线| 亚洲欧洲久久| 亚洲欧美综合网| 国产一区二区三区四区三区四| 亚洲午夜视频| 亚洲女性喷水在线观看一区| 国产伦精品一区二区三区| 欧美一级一区| 欧美一区二区精品在线| 在线看片第一页欧美| 亚洲第一在线综合在线| 欧美日韩国产色站一区二区三区| 久久国产精品一区二区| 久久国产精品色婷婷| 激情六月婷婷久久| 亚洲亚洲精品在线观看 | 欧美视频在线观看免费网址| 欧美视频专区一二在线观看| 久久精品国产亚洲5555| 欧美成人日韩| 久久琪琪电影院| 国产精品久久影院| 亚洲一区视频在线观看视频| 欧美一级理论片| 亚洲国产成人久久| 亚洲二区三区四区| 在线看国产日韩| 亚洲一区在线视频| 亚洲免费小视频| 国产精品乱码人人做人人爱| 一本色道综合亚洲| 国产精品黄色| 欧美成人中文| 亚洲精品日韩一|