<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    weidagang2046的專欄

    物格而后知致
    隨筆 - 8, 文章 - 409, 評論 - 101, 引用 - 0
    數(shù)據(jù)加載中……

    MFC六大關鍵技術之運行時類型識別

    運行時類型識別(RTTI)即是程序執(zhí)行過程中知道某個對象屬于某個類,我們平時用C++編程接觸的RTTI一般是編譯器的RTTI,即是在新版本的VC++編譯器里面選用“使能RTTI”,然后載入typeinfo.h文件,就可以使用一個叫typeid()的運算子,它的地位與在C++編程中的sizeof()運算子類似的地方(包含一個頭文件,然后就有一個熟悉好用的函數(shù))。typdid()關鍵的地方是可以接受兩個類型的參數(shù):一個是類名稱,一個是對象指針。所以我們判別一個對象是否屬于某個類就可以象下面那樣:

    if (typeid (ClassName)== typeid(*ObjectName)){
    ((ClassName*)ObjectName)->Fun();
    }

      象上面所說的那樣,一個typeid()運算子就可以輕松地識別一個對象是否屬于某一個類,但MFC并不是用typeid()的運算子來進行動態(tài)類型識別,而是用一大堆令人費解的宏。很多學員在這里很疑惑,好象MFC在大部分地方都是故作神秘。使們大家編程時很迷惘,只知道在這里加入一組宏,又在那兒加入一個映射,而不知道我們?yōu)槭裁匆尤脒@些東東。

      其實,早期的MFC并沒有typeid()運算子,所以只能沿用一個老辦法。我們甚至可以想象一下,如果MFC早期就有template(模板)的概念,可能更容易解決RTTI問題。

      所以,我們要回到“古老”的年代,想象一下,要完成RTTI要做些什么事情。就好像我們在一個新型(新型到我們還不認識)電器公司里面,我們要識別哪個是電飯鍋,哪個是電磁爐等等,我們要查看登記的各電器一系列的信息,我們才可以比較、鑒別,那個東西是什么!
    要登記一系列的消息并不是一件簡單的事情,大家可能首先想到用數(shù)組登記對象。但如果用數(shù)組,我們要定義多大的數(shù)組才好呢,大了浪費空間,小了更加不行。所以我們要用另一種數(shù)據(jù)結構——鏈表。因為鏈表理論上可大可小,可以無限擴展。

      鏈表是一種常用的數(shù)據(jù)結構,簡單地說,它是在一個對象里面保存了指向下一個同類型對象的指針。我們大體可以這樣設計我們的類:

    struct CRuntimeClass
    {
    ……類的名稱等一切信息……
    CRuntimeClass * m_pNextClass;//指向鏈表中下一CRuntimeClass對象的指針
    };

      鏈表還應該有一個表頭和一個表尾,這樣我們在查鏈表中各對象元素的信息的時候才知道從哪里查起,到哪兒結束。我們還要注明本身是由哪能個類派生。所以我們的鏈表類要這樣設計:

    struct CRuntimeClass
    {
    ……類的名稱等一切信息……
    CRuntimeClass * m_PBaseClass;//指向所屬的基類。
    CRuntimeClass * m_pNextClass;//定義表尾的時候只要定義此指針為空就可以 了。
    static CRuntimeClass* pFirstClass;//這里表頭指針屬于靜態(tài)變量,因為我們知道static變量在內(nèi)存中只初始化一次,就可以為各對象所用!保證了各對象只有一個表頭。
    };

      有了CRuntimeClass結構后,我們就可以定義鏈表了:

    static CRuntimeClass classCObject={NULL,NULL};//這里定義了一個CRuntimeClass對象,

      因為classCObject無基類,所以m_pBaseClass為NULL。因為目前只有一個元素(即目前沒有下一元素),所以m_pNextClass為NULL(表尾)。

      至于pFirstClass(表頭),大家可能有點想不通,它到什么地方去了。因為我們這里并不想把classCObject作為鏈表表頭,我們還要在前面插入很多的CRuntimeClass對象,并且因為pFirstClass為static指針,即是說它不是屬于某個對象,所以我們在用它之前要先初始化:

    CRuntimeClass* CRuntimeClass::pFirstClass=NULL;

      現(xiàn)在我們可以在前面插入一個CRuntimeClass對象,插入之前我得重要申明一下:如果單純?yōu)榱诉\行時類型識別,我們未必用到m_pNextClass指針(更多是在運行時創(chuàng)建時用),我們關心的是類本身和它的基類。這樣,查找一個對象是否屬于一個類時,主要關心的是類本身及它的基類:

    CRuntimeClass classCCmdTarget={ &classCObject, NULL};
    CRuntimeClass classCWnd={ &classCCmdTarget ,NULL };
    CRuntimeClass classCView={ &classCWnd , NULL };

      好了,上面只是僅僅為一個指針m_pBaseClass賦值(MFC中真正CRuntimeClass有多個成員變量和方法),就連接成了鏈表。假設我們現(xiàn)在已全部構造完成自己需要的CRuntimeClass對象,那么,這時候應該定義表頭。即要用pFirstClass指針指向我們最后構造的CRuntimeClass對象——classCView。

    CRuntimeClass::pFirstClass=&classCView;

      現(xiàn)在鏈表有了,表頭表尾都完善了,問題又出現(xiàn)了,我們應該怎樣訪問每一個CRuntimeClass對象?要判斷一個對象屬于某類,我們要從表頭開始,一直向表尾查找到表尾,然后才能比較得出結果嗎。肯定不是這樣!

      大家可以這樣想一下,我們構造這個鏈表的目的,就是構造完之后,能夠按主觀地拿一個CRuntimeClass對象和鏈表中的元素作比較,看看其中一個對象中否屬于你指定的類。這樣,我們需要有一個函數(shù),一個能返回自身類型名的函數(shù)GetRuntimeClass()。

      上面簡單地說一下鏈表的過程,但單純有這個鏈表是沒有任何意義。回到MFC中來,我們要實現(xiàn)的是在每個需要有RTTI能力的類中構造一個CRuntimeClass對象,比較一個類是否屬于某個對象的時候,實際上只是比較CRuntimeClass對象。

      如何在各個類之中插入CRuntimeClass對象,并且指定CRuntimeClass對象的內(nèi)容及CRuntimeClass對象的鏈接,這里起碼有十行的代碼才能完成。在每個需要有RTTI能力的類設計中都要重復那十多行代碼是一件乏味的事情,也容易出錯,所以MFC用了兩個宏代替這些工作,即DECLARE_DYNAMIC(類名)和IMPLEMENT_DYNAMIC(類名,基類名)。從這兩個宏我們可以看出在MFC名類中的CRuntimeClass對象構造連接只有類名及基類名的不同!

      到此,可能會有朋友問:為什么要用兩個宏,用一個宏不可以代換CRuntimeClass對象構造連接嗎?個人認為肯定可以,因為宏只是文字代換的游戲而已。但我們在編程之中,頭文件與源文件是分開的,我們要在頭文件頭聲明變量及方法,在源文件里實具體實現(xiàn)。即是說我們要在頭文件中聲明:

    public:
    static CRuntimeClass classXXX //XXX為類名
    virtual CRuntime* GetRuntimeClass() const;

      然后在源文件里實現(xiàn):

    CRuntimeClass* XXX::classXXX={……};
    CRuntime* GetRuntimeClass() const;
    { return &XXX:: classXXX;}//這里不能直接返回&classXXX,因為static變量是類擁有而不是對象擁有。

      我們一眼可以看出MFC中的DECLARE_DYNAMIC(類名)宏應該這樣定義:

    #define DECLARE_DYNAMIC(class_name) public: static CRuntimeClass class##class_name;
    virtual CRuntimeClass* GetRuntimeClass() const;

      其中##為連接符,可以讓我們傳入的類名前面加上class,否則跟原類同名,大家會知道產(chǎn)生什么后果。

      有了上面的DECLARE_DYNAMIC(類名)宏之后,我們在頭文件里寫上一句:

    DECLARE_DYNAMIC(XXX)

      宏展開后就有了我們想要的:

    public:
    static CRuntimeClass classXXX //XXX為類名
    virtual CRuntime* GetRuntimeClass() const;

      對于IMPLEMENT_DYNAMIC(類名,基類名),看來也不值得在這里代換文字了,大家知道它是知道回事,宏展開后為我們做了什么,再深究真是一點意義都沒有!

      有了此鏈表之后,就像有了一張存放各類型的網(wǎng),我們可以輕而易舉地RTTI。CObject有一個函數(shù)BOOL IsKindOf(const CRuntimeClass* pClass) const;,被它以下所有派生員繼承。

      此函數(shù)實現(xiàn)如下:

    BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
    {
    CRuntimeClass* pClassThis=GetRuntimeClass();//獲得自己的CRuntimeClass對象指針。
    while(pClassThis!=NULL)
    {
    if(pClassThis==pClass) return TRUE;
    pClassThis=pClassThis->m_pBaseClass;//這句最關鍵,指向自己基類,再回頭比較,一直到盡頭m_pBaseClass為NULL結束。
    }
    return FALSE;
    }

      說到這里,運行時類型識別(RTTI)算是完成了。寫這篇文章的時候,我一直重感冒。我曾一度在想,究竟寫這東西是為了什么。因為如果我把這些時間用在別的地方(甚至幫別人打打字),應該有數(shù)百元的報酬。

      是什么讓“嗜財如命”的我繼續(xù)寫下去?我想,無非是想交幾個計算機的朋友而已。計算機是大家公認高科技的東西,但學習它的朋友大多只能默默無聞,外界的朋友也不知道怎么去認識你。程序員更不是“潮流”的東西,更加得不到別人的認可。

      有一件個人認為很典型的事情,有一天,我跟一個朋友到一個單位里面。里面有一個女打字員。朋友看著她熟練的指法,心悅誠服地說:“她的電腦水平比你的又高了一個很高的層次!”,那個女的打字高手亦自豪地說:“我靠電腦為生,電腦水平肯定比你(指筆者)的好一點!換著是你,如果以電腦為生,我也不敢說好過你!”。雖然我想聲明我是計算機專業(yè)的,但我知道沒有理解,所以我只得客氣地點頭。

      選擇電腦“潮流”的東西實際是選擇了平凡,而選擇做程序員就是選擇了孤獨!幸好我不是一個專門的程序員,但即使如此,我愿意做你們的朋友,因為我愛你們!

    from: http://www.21tx.com/dev/2005/03/01/11010.html

    posted on 2006-08-13 08:17 weidagang2046 閱讀(194) 評論(0)  編輯  收藏 所屬分類: Windows

    主站蜘蛛池模板: 亚洲精品午夜无码专区| 亚洲欧美日韩一区二区三区| 久久久久久免费视频| 亚洲hairy多毛pics大全| 在线亚洲人成电影网站色www| 久久国产色AV免费看| 国产成人亚洲精品无码AV大片| 亚洲人成人无码网www电影首页 | 国产福利免费视频| 亚洲网站在线播放| 亚洲福利精品一区二区三区| 99精品热线在线观看免费视频 | 无人视频在线观看免费播放影院| 久久久久久久久亚洲| 日本一区免费电影| 57pao一国产成永久免费| 免费人成动漫在线播放r18| 亚洲视频在线观看网站| 亚洲成人国产精品| 曰曰鲁夜夜免费播放视频| 二区久久国产乱子伦免费精品 | 中文字幕亚洲免费无线观看日本 | 成人免费视频77777| 巨胸狂喷奶水视频www网站免费| 99久久国产亚洲综合精品| 亚洲第一AAAAA片| 午夜亚洲国产成人不卡在线| 永久在线免费观看| 怡红院免费全部视频在线视频| 亚洲精品GV天堂无码男同| 亚洲视频在线免费播放| 久久综合亚洲色HEZYO国产| 日韩免费视频在线观看| 3344免费播放观看视频| 99久久免费国产精品热| 无码色偷偷亚洲国内自拍| 亚洲最新中文字幕| 亚洲日韩区在线电影| 国产V亚洲V天堂无码| 亚洲国产一区二区三区| 国产精品成人免费综合|