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

posts - 1,  comments - 6,  trackbacks - 0

??? 在 Java C #等語(yǔ)言或者說(shuō)其類庫(kù)中,都實(shí)現(xiàn)了事件模型。而 c++ 語(yǔ)言本身并沒(méi)有定義事件機(jī)制,并且在目前眾多優(yōu)秀的 c++ 類庫(kù),包括 STL Boost 等都沒(méi)有實(shí)現(xiàn)類似的事件機(jī)制。當(dāng)我們被 MFC 的消息搞得頭昏眼花之時(shí),是否有沖動(dòng)自己去實(shí)現(xiàn)一個(gè)簡(jiǎn)單的事件模型呢。我想,有著相同想法的人肯定很多,而真正動(dòng)手來(lái)寫(xiě)可能會(huì)碰到各種各樣的困難。下面就讓我們一步步來(lái)編寫(xiě)一個(gè)簡(jiǎn)單的事件模型。

?

一、 了解事件模型的機(jī)制

在開(kāi)始之前,我們有必要簡(jiǎn)單的了解一下事件模型的機(jī)制。事實(shí)上,事件模型的機(jī)制不止一種, Java c# 的事件機(jī)制就不太一樣,不過(guò)事件模型的基礎(chǔ)都是一樣,那就是一般都使用 Observer 設(shè)計(jì)模式。關(guān)于 Observer 設(shè)計(jì)模式,希望詳細(xì)了解的朋友可以參考《設(shè)計(jì)模式》一書(shū),在這里我們就不詳細(xì)的介紹,只是參照 c# 的事件機(jī)制來(lái)實(shí)現(xiàn)。

c# 中,我們可以以 event 關(guān)鍵字聲明一個(gè)事件,然后我們可以將一個(gè)函數(shù)委托掛接在這個(gè)事件上,當(dāng)事件被調(diào)用時(shí),則所有掛接的函數(shù)也會(huì)被調(diào)用。這里有一個(gè)比較難以理解的詞大概是委托,其實(shí)也不難理解。委托其實(shí)就是一種函數(shù)包裝類,這種類可以把任何函數(shù)的指針保存起來(lái),等到需要調(diào)用的時(shí)候再調(diào)用,并且這種類的實(shí)例必須能夠掛接到事件之中。

看了上面這段話,是不是覺(jué)得其實(shí)事件模型也并不復(fù)雜。還想對(duì)事件模型了解得更多?我這里就不繼續(xù)了,感興趣的朋友可以查找一下相關(guān)的資料。下面我們就開(kāi)始在 c++ 中編寫(xiě)一個(gè)簡(jiǎn)單的事件模型。

?

二、 設(shè)計(jì)一個(gè)簡(jiǎn)單的 c++ 事件模型

因?yàn)橐粋€(gè)事件模型其實(shí)就是一個(gè)典型的 Observer 設(shè)計(jì)模式,因此最重要的就是 Subject( 目標(biāo)類 ) Observer( 觀察者類 ) 的設(shè)計(jì)。

首先,我們需要一個(gè)事件類,它其實(shí)是一個(gè)抽象的 Subject 。它是一個(gè)基類,所有的其他事件都從它繼承,并且用戶只需要從這個(gè)基類繼承就可以自定義事件。我們不仿將這個(gè)類定義為 CEvent CEvent 的聲明如下:

class CEvent ?

{

public :

????????

???????? typedef list < CEventHandler > data_type ;

?

???????? CEvent ();

?

???????? virtual ~ CEvent ();

?

???????? void operator ()()

???????? {

???????? ???????? data_type :: iterator it ;

??????????????????????????? ????????

?????????????????? for ( it = m_observer . begin (); it != m_observer . end (); ++ it )

?????????????????? {

?????????????????? ???????? (* it )(* this );

?????????????????? }

???????? }

?

???????? CEvent & operator += ( const CEventHandler & handler )

???????? {

???????? ???????? Register ( handler );

?????????????????? return * this ;

???????? }

?

???????? CEvent & operator -= ( const CEventHandler & handler )

???????? {

???????? ???????? UnRegister ( handler );

?????????????????? return * this ;

???????? }

?

???????? void Register ( const CEventHandler & handler )

???????? {

???????? ???????? m_observer . push_back ( handler );

???????? }

?

???????? void UnRegister ( const CEventHandler & handler )

???????? {

???????? ???????? m_observer . remove ( handler );

???????? }

?

protected :

?

???????? // 將偵聽(tīng)的所有函數(shù)或者仿函數(shù)的集合起來(lái)

???????? data_type m_observer ;

};

?

其次,這個(gè)事件可以掛接任意的函數(shù),也就是它可以保存所有的掛接函數(shù)。在 c++ 中,我們大致有三種類型的函數(shù),全局或者靜態(tài)函數(shù)、成員函數(shù)、仿函數(shù)。要在 CEvent 中實(shí)現(xiàn)一個(gè)或者多個(gè)方法來(lái)執(zhí)行掛接的任務(wù)不太現(xiàn)實(shí)。我們參考 c# 的實(shí)現(xiàn)方法,可以先實(shí)現(xiàn)一個(gè)委托類,將各種函數(shù)保存起來(lái)。然后再使用 CEvent 對(duì)這個(gè)委托類進(jìn)行掛接。我們不仿稱這個(gè)類為 CEventHandler

然后,我們的這個(gè)委托類需要能夠保存所有的函數(shù)。在 c++ 里,我們能夠很容易的得到函數(shù)的指針,只需要在函數(shù)名前加 & ,但是各種函數(shù),特別是成員函數(shù)它是沒(méi)有類型的,這就要有一種機(jī)制,將所有的函數(shù)轉(zhuǎn)換為同一種類型。因?yàn)楹瘮?shù)是沒(méi)有類型,也相當(dāng)于每一個(gè)函數(shù)都是一種類型,解決這個(gè)問(wèn)題的方法其實(shí)就是使用模板類。因此,我們先定義一個(gè)虛基類 CFunImpl 。對(duì)三種不同的函數(shù),我們分別從 CfunImpl 繼承三種不同的子類, CstaticFun CmemFun,CFunctor CstaticFun 表示全局的或者靜態(tài)的函數(shù),不過(guò)這必須是一個(gè)模板類,對(duì)于每一個(gè)靜態(tài)或者全局函數(shù),都是模板類的一個(gè)特化。類聲明的代碼如下:

template < typename Fun >

???????? class CStaticFun : public CFunImpl

???????? {

???????? public :

?

???????? ???????? CStaticFun ( const Fun & fun ) : m_fun ( fun ){};

??????????????????

?????????????????? virtual ~ CStaticFun ()

?????????????????? {

?????????????????? }

???????? protected :

?????????????????? Fun m_fun ;

???????? };

?

對(duì)于 CmemFun 類,我們?nèi)绶ㄅ谥疲贿^(guò)我們這時(shí)需要保存兩個(gè)成員變量,一個(gè)是成員函數(shù)的指針,另一個(gè)則是該成員函數(shù)所屬的對(duì)象的指針。類聲明的代碼如下:

?

template < typename PointerToObj , typename PointerToMemFun >

???????? class CMemFun : public CFunImpl

???????? {

???????? public :

?

???????? ???????? CMemFun ( const PointerToObj & pObj , PointerToMemFun pMemFn )

??????????????????????????? : m_pObj ( pObj ), m_pMemFun ( pMemFn )

?????????????????? {

?????????????????? }

?

virtual ~ CMemFun ()

?????????????????? {

?????????????????? }

??????????????????

???????? protected :

???????? ???????? PointerToObj m_pObj ;

???????? ???????? PointerToMemFun m_pMemFun ;

};

?

對(duì)于仿函數(shù),我們這里先不講,因?yàn)榉潞瘮?shù)使用得很少,并且這還涉及到仿函數(shù)的概念,有興趣的朋友可以在閱讀完本文之后自己來(lái)實(shí)現(xiàn)。

好,到現(xiàn)在為止,我們可以將所有的函數(shù)使用 CfunImpl 來(lái)表示了。因此,我們可以在委托類 CEventHandler 中保存 CfunImpl* 來(lái)達(dá)到我們的目的。 CEventHandler 的聲明如下:

???????? class CEventHandler ?

???????? {

???????? public :

?????????????????? virtual ~ CEventHandler ()

?????????????????? {

?????????????????? ???????? Clear ();

?????????????????? }

?

???????? ???????? template < class Fun >

???????? ???????? CEventHandler ( const Fun & fun )

??????????????????????????? : m_pImpl ( new CStaticFun < Fun >( fun ))

?????????????????? {}

??????????????????

???????? ???????? CEventHandler ( const CEventHandler & fun )

??????????????????????????? : m_pImpl ( NULL )

?????????????????? {

?????????????????? ???????? * this = fun ;

?????????????????? }

?

?????????????????? void Clear ()

?????????????????? {

??????????????????????????? if ( m_pImpl )

??????????????????????????? {

??????????????????????????? ???????? delete m_pImpl ;

??????????????????????????? ???????? m_pImpl = NULL ;

??????????????????????????? }

?????????????????? }

?

???????? ???????? CEventHandler & operator = ( const CEventHandler & fun )

?????????????????? {

?????????????????? ???????? Clear ();

?

??????????????????????????? if ( fun . m_pImpl )

??????????????????????????? {

??????????????????????????? ???????? m_pImpl = fun . m_pImpl -> Clone ();

??????????????????????????? }

?

?????????????????? ???????? return * this ;

?????????????????? }

??????????????????

?????????????????? // 成員函數(shù)

???????? ???????? template < typename PointerToObj , typename PointerToMemFun >

?????????????????? ???????? CEventHandler ( const PointerToObj & pObj , const PointerToMemFun & pMemFun )

??????????????????????????? : m_pImpl ( new CMemFun < PointerToObj , PointerToMemFun >( pObj , pMemFun ))

?????????????????? {}

?

?????????????????? void operator ()( CEvent & e )

?????????????????? {

if ( m_pImpl )

??????????????????????????? {

??????????????????????????? ???????? (* m_pImpl )( e );

}

?????????????????? }

?

?????????????????? bool operator == ( const CEventHandler & handler )

?????????????????? {

??????????????????????????? if ( m_pImpl == NULL || handler . m_pImpl == NULL )

??????????????????????????? {

??????????????????????????? ???????? return true ;

??????????????????????????? }

?

??????????????????????????? if ( typeid ( m_pImpl ) == typeid ( handler . m_pImpl ))

??????????????????????????? {

??????????????????????????? ???????? return (* m_pImpl ) == (*( handler . m_pImpl ));

??????????????????????????? }

?

?????????????????? ???????? return false ;

?????????????????? }

?

???????? protected :

???????? ???????? CFunImpl * m_pImpl ;

?

???????? };

?

不過(guò)要實(shí)現(xiàn)事件機(jī)制,我們還需要 CfunImpl* 的子類必須實(shí)現(xiàn)幾個(gè)方法。

第一個(gè)方法就是調(diào)用函數(shù)的方法,我們這里要求重載 void operator()(CEvent& e); 來(lái)達(dá)到目的。

第二個(gè)方法就是 operator== ,為什么需要這個(gè)方法呢。因?yàn)閷?duì)于 CEvent 來(lái)說(shuō),調(diào)用 UnRegister() 時(shí),我們必須找到我們使用 Register() 添加到 list 中的函數(shù),這時(shí)我們需要判斷兩個(gè) CEventHandler 對(duì)象是否相等,這是件麻煩事情。 CEventHandler 保存的是 CFunImpl 的指針,好吧,這個(gè)我們就要求 CfunImpl 的子類必須實(shí)現(xiàn)重載 operator==

第三個(gè)方法,從 CfunImpl 繼承必須實(shí)現(xiàn) Clone() 方法。 Clone() 方法可以讓 CEventHandler 實(shí)現(xiàn)拷貝。具體的實(shí)現(xiàn)方法我們可以查看源碼。

?

三、 使用事件模型

一個(gè)簡(jiǎn)單的事件模型基本完成了。現(xiàn)在我們可以編寫(xiě)一個(gè)例子來(lái)演示一下如何來(lái)使用這個(gè)事件模型。其實(shí)使用起來(lái)很簡(jiǎn)單。

我們可以聲明一個(gè) CEvent 或者 CEvent 子類的實(shí)例。讓需要監(jiān)聽(tīng)的函數(shù)掛接到這個(gè) CEvent 中,我們實(shí)現(xiàn)了 Register() 函數(shù)和 += 操作符,都可以使用。掛接的語(yǔ)句就像這樣:

CEvent evt;

CobserverTest obj;

evt += CEventHandler (& obj , &( CObserverTest :: OnStartEvent ));

當(dāng)事件的 operator() 方法調(diào)用時(shí),就會(huì)自動(dòng)調(diào)用我們的監(jiān)聽(tīng)函數(shù)。具體的例子可以查看提供的源代碼。

?

四、 模型的缺陷和改進(jìn)

到現(xiàn)在為止,我們終于實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的事件模型。它可以有效的工作,并且與平臺(tái)無(wú)關(guān)。當(dāng)然,要求你的編譯器盡量的支持 c++ 標(biāo)準(zhǔn)。如果你的編譯器對(duì) c++98 標(biāo)準(zhǔn)支持不夠,也許它不能夠工作正常。筆者在 VC6SP6 VC2005 中測(cè)試均通過(guò)。

不過(guò)這個(gè)模型還有可以改進(jìn)的余地。其一、目前只是支持同步操作,即當(dāng)你的事件進(jìn)行調(diào)用時(shí)是在同一線程里順序進(jìn)行。要改進(jìn)到支持異步調(diào)用就必須在每次調(diào)用時(shí)在一個(gè)新的線程中進(jìn)行調(diào)用。因此我們需要一個(gè)線程機(jī)制來(lái)完成這個(gè)工作。如果在一個(gè)特定的平臺(tái)中使用,如 VC 中,我們可以在響應(yīng)函數(shù)中創(chuàng)建一個(gè)新的線程。

其二、目前的所有的函數(shù)參數(shù)必須為 (CEvent& e) ,不能寫(xiě)成 (CchildEvent& e) 。要對(duì)這個(gè)限制進(jìn)行改進(jìn),就需要編譯器支持虛模板成員函數(shù)的機(jī)制。不過(guò)在 VC6 VC2005 中,均不支持這種特性。因此要么尋求它法,要么就等到編譯器的支持吧。

其三、線程安全,這個(gè)簡(jiǎn)單的事件模型使用到了 STL 中的 list 組件,但是并非所有的 list 實(shí)現(xiàn)都是線程安全的。建議大家采用 stlport ,因?yàn)樗膶?shí)現(xiàn)是線程安全的,如果沒(méi)有采用線程安全的實(shí)現(xiàn),那么在調(diào)用 Register UnRegister 時(shí)最好能夠?qū)崿F(xiàn)互斥。

?

限于筆者知識(shí)水平和文筆有限,不當(dāng)之處肯定很多。若你有好的想法和建議,可以 email 告訴我。本文中所涉及到的所有源碼可以從這里下載http://m.shnenglu.com/Files/lunny/CEventModel.rar

?

????????????? ???????????????????? ???????????????????? ?????? ????????????? ???????????????????? ????????????? 肖倫文

xiaolunwen@hotmail.com
posted on 2006-07-30 20:48 風(fēng)間蒼月 閱讀(4314) 評(píng)論(6)  編輯 收藏 引用

只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   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>
            黄色亚洲精品| 欧美一区二区视频观看视频| 欧美日韩另类字幕中文| 久久久青草婷婷精品综合日韩| 欧美午夜精品理论片a级按摩| 99精品欧美一区| 亚洲欧美不卡| 韩国三级电影一区二区| 99精品久久久| 欧美国产日韩一区| 一区二区三区三区在线| 久久国产毛片| 亚洲免费观看视频| 国产一区二区高清| 国产精品一区二区久久| 欧美黄色片免费观看| 亚洲少妇诱惑| 亚洲国产高潮在线观看| 亚洲男人的天堂在线| 国产一区二区精品| 欧美精品色网| 欧美va天堂va视频va在线| 久久久另类综合| 亚洲综合日韩| 日韩午夜中文字幕| 亚洲国产经典视频| 亚洲成色777777女色窝| 欧美在线一级视频| 一区二区三区波多野结衣在线观看| 国产一区二区三区免费不卡| 国产精品久久久久久av下载红粉 | 最新国产精品拍自在线播放| 久久久久久久一区二区| 99re66热这里只有精品3直播| 欲色影视综合吧| 国产婷婷一区二区| 黄色精品免费| 韩日视频一区| 91久久精品国产91久久性色tv| 欧美国产欧美综合| 麻豆成人在线| 亚洲男女自偷自拍| 亚洲激情成人在线| 久久精品在线| 亚洲午夜视频在线观看| aⅴ色国产欧美| 国产一区二区三区丝袜| 欧美午夜宅男影院| 免费成人性网站| 久久久精品国产99久久精品芒果| 亚洲精品小视频在线观看| 欧美**人妖| 欧美福利影院| 亚洲区第一页| 久久久无码精品亚洲日韩按摩| 欧美精品在线免费| 久久一区激情| 国产精品久久久久久影院8一贰佰 国产精品久久久久久影视 | 性久久久久久久久久久久| 欧美激情偷拍| 先锋影院在线亚洲| 国产精品久久久久9999吃药| 亚洲激情另类| 亚洲国产精品久久久久婷婷老年| 日韩亚洲成人av在线| 亚洲一区二区四区| 狠狠v欧美v日韩v亚洲ⅴ| 美国成人直播| 免费看的黄色欧美网站| 亚洲天堂偷拍| 国产精品久久精品日日| 亚洲深夜影院| 一区二区激情小说| 久久国产精品亚洲77777| 国内精品久久久久伊人av| 国产精品久久一级| 欧美成人免费小视频| 性欧美大战久久久久久久久| 久热爱精品视频线路一| 一区二区激情小说| 欧美激情一区二区三区不卡| 亚洲一区二区三区四区五区黄| 国产美女精品| 亚洲精品久久久久久一区二区| 久久精品99国产精品| 农夫在线精品视频免费观看| 一区二区三区久久精品| 欧美亚洲免费在线| 欧美成人中文字幕在线| 在线精品视频一区二区| 久久精品国产第一区二区三区最新章节| 久久九九有精品国产23| 最新日韩在线视频| 欧美日本一区二区三区| 在线观看欧美| 亚洲级视频在线观看免费1级| 国产欧美一区二区三区国产幕精品| 亚洲大片精品永久免费| 欧美激情一区在线| 欧美日韩调教| 欧美a级大片| 亚洲成人在线免费| 最新日韩在线视频| 欧美国产日韩一区| 黄色国产精品一区二区三区| 欧美日韩在线播放三区四区| 久久午夜精品一区二区| 欧美乱在线观看| 国产精品私房写真福利视频| 亚洲黄色成人| 久久久久天天天天| 亚洲卡通欧美制服中文| 欧美性猛交xxxx免费看久久久 | 亚洲激情中文1区| 久久久久久尹人网香蕉| 欧美电影在线观看完整版| 在线视频精品| 欧美性做爰猛烈叫床潮| 亚洲精品字幕| 欧美在线91| 欧美综合国产精品久久丁香| 久久精品日韩| 亚洲日本精品国产第一区| 欧美与黑人午夜性猛交久久久| 久久久精品日韩欧美| 黑丝一区二区| 亚洲国产成人不卡| 国产欧美一区二区精品忘忧草 | 免播放器亚洲一区| 亚洲午夜在线视频| 欧美国产日韩精品免费观看| 久久成人免费网| 亚洲欧美成人| 亚洲欧美日韩精品久久奇米色影视 | 亚洲欧美在线一区| 亚洲经典视频在线观看| 亚洲——在线| 欧美一区日韩一区| 欧美高清在线视频观看不卡| 欧美国产日韩一区| 国产一区91精品张津瑜| 亚洲精品一区二区在线观看| 狠狠色丁香婷综合久久| 午夜精品在线观看| 久久天堂成人| 黄色成人在线网站| 老司机成人网| 91久久精品久久国产性色也91| 亚洲国产日韩美| 欧美另类视频在线| 欧美一级在线视频| 欧美国产日产韩国视频| **网站欧美大片在线观看| 夜夜嗨av一区二区三区| 蜜桃伊人久久| 欧美国产日韩a欧美在线观看| 亚洲人体大胆视频| 亚洲欧美激情四射在线日 | 亚洲一区免费观看| 亚洲日本一区二区| 欧美成人高清视频| 亚洲图片欧美日产| 免费精品视频| 久久久国产亚洲精品| 免费在线成人av| 亚洲人成在线播放| 国产热re99久久6国产精品| 欧美在线啊v| 欧美日韩亚洲视频| 欧美国产一区视频在线观看| 在线视频日韩精品| 欧美女同在线视频| 最近看过的日韩成人| 美女精品网站| 欧美一区二区三区精品| 欧美午夜在线视频| 欧美黄污视频| 麻豆久久精品| 国产精品亚洲综合久久| 在线播放豆国产99亚洲| 国产一区二区三区久久久| 国内外成人在线| 欧美国产视频在线| 国产精品美女www爽爽爽| 久久婷婷影院| 欧美日韩综合久久| 亚洲激情欧美| 国产精品视频内| 日韩视频一区二区三区在线播放| 欧美成人a视频| 亚洲精品在线观| 亚洲综合激情| 99成人免费视频| 亚洲免费网址| 国语自产偷拍精品视频偷| 一区二区三区.www| 久久久久中文| 免费在线观看一区二区| 理论片一区二区在线| 亚洲一区欧美|