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

Event Programming in C++ (Part I)


Q:
微軟的.NET框架讓我們能夠為托管類定義事件并通過代理和+=操作符對其進行處理.那么在本地C++中有沒有同樣的方法呢,它看起來很有用.

      某些讀者

 

A:事實上確實有! Visual C++? .NET有種稱為統一事件模型的東西能讓你用和托管類同樣的途徑實現本地事件(通過__event關鍵字),但是本地事件有些微軟都沒計劃要修正的隱晦的技術問題,因此他們讓我正式的去阻止你們用它.這是不是意味著C++程序員們只有生活在沒有事件的世界中呢?當然不是!不止一種方法能剝貓皮(血腥!).我將告訴你們怎樣有條不紊的實現自己華麗的事件系統.

在此之前,我先大概說下關于事件和事件編程的東西,這很重要!在現在這個年月你不能對事件的理解沒有一個堅實的基礎就來編寫代碼--它們是什么?什么時候該用它們?

成功的設計全是針對降低復雜性的.很久以前,當函數還被稱作子程序”(我本人為證,我確信),降低復雜性的主要途徑就是自上而下的編程.你從一個高層次的目的入手如為宇宙建模”,然后把它分解成較小的任務如為銀河系建模為太陽系建模”,然后... 直到這些任務變得簡單到能在一個函數里實現.自上而下的設計仍然被運用在在程序設計中,但是當系統要對發生順序不確定的實時事件作出響應時,它就不能很好的工作了.一個經典的例子就是必須對用戶操作如點擊一個按鍵或移動鼠標作出響應的GUI程序.事實上, 圖形用戶接口的出現很大程度上刺激了事件編程的發展.

在自上而下的模式中,處在頂層的高層次模塊通過調用像DoThis,DoThat的函數來驅使低層次模塊來完成不同的任務.但是低層次模塊遲早需要向上回饋.Windows,你可以讓矩形或橢圓形畫出它自己,但最終Windows需要調用你的應用程序來顯示它的窗口.但是你的應用程序甚至還根本不存在,它還在計劃中!那么Windows怎樣才能知道該去調用哪個函數呢?這里就是事件的用武之地.

                                       圖自上而下 vs 自下而上

所有基于Windows的應用程序-不管是直接用C編寫,還是用封裝在MFC或者.NET框架中的類-的核心就是一個處理諸如WM_PAINT,WM_SETFOCUS這樣的消息的窗口過程.(或者說是MFC.NET)實現了這個窗口過程并且把它傳遞給Windows操作系統.當需要描繪,改變焦點或者激活窗口時,Windows用適當的消息代碼通知你的程序.這些消息就是事件.你的窗口過程就是事件處理者.

如果說過程編程是自上而下,那事件編程就是自下而上.在一個典型的軟件系統中,函數調用是從較高層模塊流向較底層模塊;然而事件以相反的方向流動.1說明了這個模式.當然,我們的現實世界并不總是這么層次分明的.

很多軟件系統看起來更像圖2所述.


                     




                                          圖混合模式

那么嚴格來講到底什么是事件呢?本質上來說它是一個回調.模塊用調用你在運行時提供的函數這條途徑取代了了調用一個函數名稱在編譯時究已知的函數.Windows,它就叫窗口過程..NET框架中它就叫委托.不論術語怎么講,事件為軟件模塊提供了一條調用直到運行時才知道的函數的途徑.回調就是事件處理程序.激發一個事件就意味著會調用事件處理程序.第一個接收者交給發送者一個注冊事件處理程序的指針.

下面是些我們通常會用到事件的一些情形.

向客戶端通報實時事件:用戶按下一個按鍵;時間到了午夜;風扇停止,CPU著火了.

 

報告一個時間很長的操作的進展情況:當拷貝文件或者搜索一個海量數據庫時,組件可能會定期的喚起一個事件來報告已經拷貝了多少文件或者已經搜索了多少條記錄.

 

報告一些重要的或者感興趣的事情的發生:如果你在你的程序中用IWebBrowser2訪問Microsoft Internet Explorer,在導航到一個新頁面之前和之后或者當它創建了一個新窗口等等它都會通報你.

 

調用庫函數:C運行時庫函數 qsort可以對對象數組排序,但是你必須將要比較的對象提供給這個函數.很多STL容器都有這些技巧.大多數程序員不會說qsort回調了一個事件,但是沒理由你不能這么想.它是”time to compare”事件.

 

一些讀者偶爾會問:異常和事件的區別是什么?最主要的區別是異常描述的是假定不會發生卻發生了的意想不到的情形.比如你的程序用光了內存或用零做了除數.,這就是你不希望發生的異常的情形,一旦它們發生了,你的程序必須對它進行處理.然而事件是正常的日常操作的一部分并且完全是意料之中的.用戶移動了鼠標或按下一個按鍵.瀏覽器導航到新頁面.從控制流的角度來看,事件就是一個函數調用,而異常是跨越調用棧的長跳轉.

對于事件最普遍的誤解是:它們是異步的.盡管事件經常被用來處理用戶輸入及其他異步操作,事件本身是同步發生的.激活一個事件和調用事件處理是一回事.它看起來像下面這段偽碼:

// raise Foo event

for (/* each registered object */) {

  obj->FooHandler(/* args */);

}

控制權立即被交給事件處理程序,直到它處理完成才會返回.有些系統提供了異步方式激活事件的途徑;Windows讓你用PostMessage替代SendMessage.控制權立即從PostMessage回收,而消息稍后才會被處理.

但是.NET框架事件和我在此討論的事件都是一旦被激活就立刻被處理.當然,你總是能夠從運行在單獨的線程的代碼里激活事件,或者用異步委托調用來執行導致事件異步(相對于主線程)發生的線程池里的每一個事件處理程序.

Windows處理事件的方式(擁有大量窗口過程和類型一致的WPARAM/LPARAM參數),以現代程序設計的標準來看也是相當簡單的.因此所有的Windows程序都在用這一套機制,即使是今天.有些程序員甚至創建不可視窗口來傳遞事件.窗口過程并不是真實的事件機制,原因在于Windows只允許每個窗口只能有一個窗口過程,因而如果每個窗口過程都調用它之前的,則多個窗口過程就能鏈接起來.這種流程就是子過程.在真實的事件系統中,可以不分層次的為同樣的事件注冊不只一個的接收者.

.NET框架中,事件機制很健全.任何對象都能定義事件,并且多個對象可以監聽它們..NET,事件通過委托(.NET中回調的替代詞)來工作.更重要的是委托是類型安全的,不再有void*WPARAM/LPARAM之類的東西.

在托管擴展中,要定義一個事件可以用__event關鍵字.例如Windows::Forms中的Button類有一個Click事件:

// in Button class

public:

  __event EventHandler* Click;

事件處理程序是一個接受一個ObjectEventArgs參數的函數委托:

public __delegate void EventHandler(

   Object* sender,

   EventArgs* e

);

要接收事件你要實現一個有正確的參數的處理者成員函數并創建一個委托封裝它,然后調用事件操作符”+=”來注冊你的處理函數/委托.對于Click事件,它看起來像這樣:

// event handler

void CMyForm::OnAbort(Object* sender, EventArgs *e)

{

  ...

}

// register my handler

m_abortButton->Click += new EventHandler(this, OnAbort);

注意處理函數必須和委托定義的參數一樣.所有這些都能在MSDNManaged Extensions 101找到.但是你問的并不是托管事件而是本地事件-怎樣在本地C++中實現事件?C++沒有內建的事件機制,你能做什么呢?你能用typedef來定義一個回調函數然后讓客戶接受它,有點像qsort那頂舊帽子.更不畢說當你要處理幾個事件時會有多麻煩.當你想用成員函數取代靜態外部函數來作為事件處理函數,它會尤其丑陋!

定義事件更好的方法是創建一個接口.COM就是這么做的.但是你不畢用C++實現所有的COM代碼,你可以用一個簡單的類.我以自己寫的一個類名為CPrimerCalculator的類為例,它用來找出的質數.當它運行時,它會激活兩種類型的事件:一個進度事件和一個完成事件.這些事件由IPrimeEvents接口定義..NETCOM的角度來看IPrimeEvents就是一個接口;它就是一個普通而古老的定義了簽名(參數和返回類型)C++抽象類.所有處理CPrimerCalculator事件的客戶都必須實現IPrimeEvents,然后調用CPrimeCalculator::Register注冊它們的接口.CPrimeCalculator將這些對象/接口添加到自身的鏈表中去.CPrimeCalculator測試每個整數的質數性時,它會周期性的報告截止到目前一共找到了多少質數:

// in CPrimeCalculator::FindPrimes

for (UINT p=2; p<max; p++) {

   // figure out if p is prime

   if (/* every now and then */)

      NotifyProgress(GetNumberOfPrimes());

   ...

}

NotifyDone();

CPrimeCalculator調用自己的助手函數NotifyProgressNotifyDone來激活事件.這些函數遍歷事件鏈表,調用每個客戶的合適的事件處理函數.代碼如下:

void CPrimeCalculator::NotifyProgress(UINT nFound)

{

  list<IPrimeEvents*>::iterator it;

  for (it=m_clients.begin(); it!=m_clients.end(); it++) {

    (*it)->OnProgress(nFound);

  }

}

如果你還沒忘記STL,你會明白迭代器的解除引用操作符會返回當前對象,上面代碼中的for循環里的那一行等同于下面:

IPrimeEvents* obj = *it;

obj->OnProgress(nFound);

有一個類似的不帶參數的NotifyDone函數能激發完成事件.你應該明白在客戶知道當FindPrimes返回控制權時CPrimeCalculator已經完成之前沒有必要用完成事件.除了一種情況以外你可能是對的.那就是可能不止有一個客戶為接收事件注冊了,并且很可能不是同一個客戶調用了CPrimeCalculator::FindPrimes.3就是我的PrimeCalc測試程序.PrimeCalc為質數事件實現了兩種不同的事件處理過程.第一個就是主對話框本身CMyDlg,它利用多重繼承實現了IPrimeEvents接口.這個對話框處理了OnProgressOnDone事件,它在窗口中顯示進度并且當完成是有提示音.另一個是CTracePrimeEvents,它同樣實現了IPrimeEvents接口.它的實現是顯示診斷信息.CTracePrimeEvents的目的是為了展示怎樣為同樣的事件注冊一個以上的客戶.

                     

                                    圖 3 PrimeCalc in Action

   在用CPrimeCalculator寫應用程序的程序員看來處理事件是很簡單而清晰的.IPrimeEvents派生,實現處理函數,然后注冊自己.在通過寫各種類來激發事件的程序員看來,這個過程是有點單調乏味的.首先你得定義事件接口,這還湊活.但緊接著你的寫注冊和解除注冊函數,更不畢說為每一個Foo事件寫下NotifyFoo函數.如果你有15個事件,特別是每一個NotifyFoo函數都像一個娘胎里出來似的,這就相當討厭了.

void CMyClass::NotifyFoo(/* args */)

{

  list<IPrimeEvents*>::iterator it;

  for (it=m_clients.begin(); it!=m_clients.end(); it++) {

    (*it)->OnFoo(/* args */);

  }

}

                        
                                 圖 4 PrimeCalcTraceWin中的輸出

   迭代客戶鏈表中的NotifyFoo,為每一個已注冊客戶調用適當的OnFoo處理函數,傳給它需要的任何參數.有沒有什么方法能用宏或模板或其它什么東西把它通用化來減輕這份苦差事把你從寫一些令人厭煩的樣板代碼中解放出來呢?事實上,確實有!在下個月我會向你們展示.同樣的時間,同樣的頻道.在此之前-Happy Programming!

posted on 2006-03-16 11:08 Dr.Magic 閱讀(1195) 評論(2)  編輯 收藏 引用 所屬分類: 譯海淺涉

FeedBack:
# re: Event Programming in C++ (Part I)
2006-03-19 11:26 | 編程浪子
不錯!很好的思路!!!!不過語法有些不太通順!!!哈哈!謝謝先  回復  更多評論
  
# re: Event Programming in C++ (Part I)
2006-04-17 14:38 | 猩猩
圖片也顯示不出來  回復  更多評論
  

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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在线播放| 欧美激情第三页| 亚洲国产1区| 亚洲嫩草精品久久| 在线看日韩av| 欧美精品激情blacked18| 亚洲一区www| 免费人成精品欧美精品| 正在播放日韩| 一区二区三区在线观看视频| 欧美日韩成人免费| 久久精品国产亚洲精品 | 欧美高清视频一区| 亚洲宅男天堂在线观看无病毒| 国产自产女人91一区在线观看| 欧美大片第1页| 久久国产精品久久精品国产 | 欧美1区2区| 亚洲欧美另类中文字幕| 亚洲国产精品久久人人爱蜜臀 | 亚洲电影免费观看高清完整版在线观看 | 久久综合给合| 性欧美videos另类喷潮| 日韩亚洲欧美成人一区| 一区免费观看视频| 国产精品欧美日韩一区二区| 欧美高清视频免费观看| 久久久久久久久岛国免费| 一区二区三区 在线观看视| 亚洲国产精品久久久| 久久综合狠狠综合久久激情| 午夜在线观看欧美| 一区二区三区**美女毛片| 亚洲黄色在线| 在线电影院国产精品| 国产一区日韩一区| 国产伦精品一区二区三区视频孕妇 | 欧美在线播放高清精品| 亚洲一区二区久久| 在线亚洲+欧美+日本专区| 亚洲国产日韩欧美在线99| 欧美a级理论片| 久久综合一区二区| 久久欧美中文字幕| 久久精品一二三区| 久久精品国产视频| 久久国产主播| 久久久久国色av免费观看性色| 午夜视频在线观看一区二区| 亚洲一区二区三区四区视频| 在线综合亚洲| 亚洲午夜一二三区视频| 亚洲午夜一区| 午夜视频一区二区| 欧美一站二站| 久久久青草青青国产亚洲免观| 久久国产夜色精品鲁鲁99| 久久久久久9| 美女黄色成人网| 欧美成人日本| 亚洲人成高清| 一区二区三区视频在线播放| 中文一区字幕| 亚洲欧美日韩直播| 久久久精品国产99久久精品芒果| 久久成人一区二区| 美国十次了思思久久精品导航| 欧美成人激情视频| 欧美日韩亚洲一区二区| 国产精品美女久久久久久免费| 国产乱码精品一区二区三区不卡 | 亚洲理论在线| 一本色道88久久加勒比精品 | 欧美在线看片| 猛男gaygay欧美视频| 欧美精品手机在线| 国产精品进线69影院| 国产在线拍偷自揄拍精品| 136国产福利精品导航| 亚洲免费播放| 欧美夜福利tv在线| 欧美不卡激情三级在线观看| 亚洲精品黄色| 亚洲欧美日韩国产| 久久一区欧美| 欧美日韩综合另类| 狠狠色狠狠色综合日日tαg| 亚洲国产成人av在线| 亚洲一二区在线| 卡通动漫国产精品| 日韩视频在线观看一区二区| 欧美亚洲免费| 欧美理论电影网| 国产日韩成人精品| 亚洲人成啪啪网站| 欧美在线高清| 亚洲日本成人网| 久久国产直播| 国产精品h在线观看| 伊人激情综合| 欧美一区二区三区免费视| 欧美国产在线电影| 亚洲欧洲99久久| 欧美精品1区2区3区| 国内精品视频久久| 亚洲一区视频在线观看视频| 欧美高清视频www夜色资源网| 亚洲夜晚福利在线观看| 欧美91视频| 国语自产精品视频在线看抢先版结局 | 国产日本欧美视频| 一区二区三区欧美成人| 麻豆精品一区二区综合av| 亚洲午夜精品国产| 欧美高清一区| 伊人影院久久| 久久精品官网| 亚洲一区三区电影在线观看| 欧美精品一区在线发布| 伊人男人综合视频网| 欧美在线精品免播放器视频| 日韩亚洲精品视频| 欧美成人午夜激情| 在线播放中文一区| 久久久久久久综合日本| 亚洲一区欧美一区| 国产精品vvv| 一区二区三区免费网站| 亚洲国产导航| 美腿丝袜亚洲色图| 亚洲成色777777女色窝| 久久男女视频| 久久九九国产精品怡红院| 国产日本亚洲高清| 久久国产精品久久国产精品| 这里只有精品丝袜| 欧美日韩另类在线| 亚洲视频国产视频| 夜夜狂射影院欧美极品| 欧美日韩免费高清一区色橹橹| 日韩视频中午一区| 亚洲啪啪91| 欧美日韩亚洲精品内裤| 一区二区三区欧美| 亚洲最新视频在线| 欧美午夜精品久久久久久孕妇| 一区二区三区四区五区精品| 亚洲精品久久久久久久久久久久久| 免费在线成人av| 亚洲三级毛片| 亚洲精品在线视频| 欧美性大战xxxxx久久久| 亚洲免费视频中文字幕| 亚洲在线视频免费观看| 国产亚洲高清视频| 鲁大师成人一区二区三区| 久久影院午夜片一区| 亚洲激情在线观看视频免费| 91久久国产综合久久蜜月精品| 欧美日本一区二区三区| 亚洲与欧洲av电影| 亚洲男人天堂2024| 伊人成人开心激情综合网| 欧美激情在线免费观看| 在线免费精品视频| 看欧美日韩国产| 亚洲手机在线| 欧美影院久久久| 久久精品国产亚洲aⅴ| 亚洲欧洲另类| 一区二区三区精品| 国产亚洲成年网址在线观看| 蜜桃久久av一区| 欧美日韩www| 久久国产精品久久w女人spa| 久久亚洲一区二区| 亚洲视频www| 久久精品盗摄| 在线一区二区三区做爰视频网站| 亚洲欧美高清| 亚洲三级影片|