• <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>
            隨筆 - 74, 文章 - 0, 評論 - 26, 引用 - 0
            數(shù)據(jù)加載中……

            如何在運行時確定對象類型(RTTI) 轉(zhuǎn)

            RTTI 是“Runtime Type Information”的縮寫,意思是:運行時類型信息。它提供了運行時確定對象類型的方法。本文將簡略介紹 RTTI 的一些背景知識、描述 RTTI 的概念,并通過具體例子和代碼介紹什么時候使用以及如何使用 RTTI;本文還將詳細描述兩個重要的 RTTI 運算符的使用方法,它們是 typeid 和 dynamic_cast。
                其實,RTTI 在C++中并不是什么新的東西,它早在十多年以前就已經(jīng)出現(xiàn)了。但是大多數(shù)開發(fā)人員,包括許多高層次的C++程序員對它并不怎么熟悉,更不用說使用 RTTI 來設(shè)計和編寫應(yīng)用程序了。
                一些面向?qū)ο髮<以趥鞑プ约旱脑O(shè)計理念時,大多都主張在設(shè)計和開發(fā)中明智地使用虛擬成員函數(shù),而不用 RTTI 機制。但是,在很多情況下,虛擬函數(shù)無法克服本身的局限。每每涉及到處理異類容器和根基類層次(如 MFC)時,不可避免要對對象類型進行動態(tài)判斷,也就是動態(tài)類型的偵測。如何確定對象的動態(tài)類型呢?答案是使用內(nèi)建的 RTTI 中的運算符:typeid 和 dynamic_cast。
                首先讓我們來設(shè)計一個類層次,假設(shè)我們創(chuàng)建了某個處理文件的抽象基類。它聲明下列純虛擬函數(shù):open()、close()、read()和 write():
            class File
            {
            public:
            virtual int open(const string & filename)=0;
            virtual int close(const string & filename)=0;
            //
            virtual ~File()=0; // 記住添加純虛擬析構(gòu)函數(shù)(dtor)
            };
            現(xiàn)在從 File 類派生的類要實現(xiàn)基類的純虛擬函數(shù),同時還要提供一些其他的操作。假設(shè)派生類為 DiskFile,除了實現(xiàn)基類的純虛擬函數(shù)外,還要實現(xiàn)自己的flush()和defragment()操作:
            class DiskFile: public File
            {
            public:
            int open(const string & filename);

            // 實現(xiàn)其他的純虛擬函數(shù)
            ......

            // 自己的專有操作
            virtual int flush();
            virtual int defragment();
            };
            接著,又從 DiskFile 類派生兩個類,假設(shè)為 TextFile 和 MediaFile。前者針對文本文件,后者針對音頻和視頻文件:
            class TextFile: public DiskFile
            {
            // ......
            int sort_by_words();
            };

            class MediaFile: public DiskFile
            {
            //......
            };
            我們之所以要創(chuàng)建這樣的類層次,是因為這樣做以后可以創(chuàng)建多態(tài)對象,如:
            File *pfile; // *pfile的靜態(tài)類型是 File
            if(some_condition)
            pfile = new TextFile; // 動態(tài)類型是 TextFile
            else
            pfile = new DiskFile; // 動態(tài)類型是 DiskFile
                假設(shè)你正在開發(fā)一個基于圖形用戶界面(GUI)的文件管理器,每個文件都可以以圖標方式顯示。當鼠標移到圖標上并單擊右鍵時,文件管理器打開一個菜單,每 個文件除了共同的菜單項,不同的文件類型還有不同的菜單項。如:共同的菜單項有“打開”“拷貝”、和“粘貼”,此外,還有一些針對特殊文件的專門操作。比 如,文本文件會有“編輯”操作,而多媒體文件則會有“播放”菜單。為了使用 RTTI 來動態(tài)定制菜單,文件管理器必須偵測每個文件的動態(tài)類型。利用 運算符 typeid 可以獲取與某個對象關(guān)聯(lián)的運行時類型信息。typeid 有一個參數(shù),傳遞對象或類型名。因此,為了確定 x 的動態(tài)類型是不是Y,可以用表達式:typeid(x) == typeid(Y)實現(xiàn):
            #include <typeinfo> // typeid 需要的頭文件
            void menu::build(const File * pfile)
            {
            if (typeid(*pfile)==typeid(TextFile))
            {
            add_option("edit");
            }
            else if (typeid(*pfile)==typeid(MediaFile))
            {
            add_option("play");
            }
            }
                使用 typeid 要注意一個問題,那就是某些編譯器(如 Visual C++)默認狀態(tài)是禁用 RTTI 的,目的是消除性能上的開銷。如果你的程序確實使用了 RTTI,一定要記住在編譯前啟用 RTTI。使用 typeid 可能產(chǎn)生一些將來的維護問題。假設(shè)你決定擴展上述的類層次,從MediaFile 派生另一個叫 LocalizeMedia 的類,用這個類表示帶有不同語言說明文字的媒體文件。但 LocalizeMedia 本質(zhì)上還是個 MediaFile 類型的文件。因此,當用戶在該類文件圖標上單擊右鍵時,文件管理器必須提供一個“播放”菜單。可惜 build()成員函數(shù)會調(diào)用失敗,原因是你沒有檢查這種特定的文件類型。為了解決這個問題,你必須象下面這樣對 build() 打補丁:
            void menu::build(const File * pfile)
            {

            //......

            else if (typeid(*pfile)==typeid(LocalizedMedia))
            {
            add_option("play");
            }
            }
                唉,這種做法真是顯得太業(yè)余了,以后每次添加新的類,毫無疑問都必須打類似的補丁。顯然,這不是一個理想的解決方案。這個時候我們就要用到 dynamic_cast,這個運算符用于多態(tài)編程中保證在運行時發(fā)生正確的轉(zhuǎn)換(即編譯器無法驗證是否發(fā)生正確的轉(zhuǎn)換)。用它來確定某個對象是 MediaFile 對象還是它的派生類對象。dynamic_cast 常用于從多態(tài)編程基類指針向派生類指針的向下類型轉(zhuǎn)換。它有兩個參數(shù):一個是類型名;另一個是多態(tài)對象的指針或引用。其功能是在運行時將對象強制轉(zhuǎn)換為目標類型并返回布爾型結(jié)果。也就是說,如果該函數(shù)成功地并且是動態(tài)的將 *pfile 強制轉(zhuǎn)換為 MediaFile,那么 pfile的動態(tài)類型是 MediaFile 或者是它的派生類。否則,pfile 則為其它的類型:
            void menu::build(const File * pfile)
            {
            if (dynamic_cast <MediaFile *> (pfile))
            {
            // pfile 是 MediaFile 或者是MediaFile的派生類 LocalizedMedia
            add_option("play");
            }
            else if (dynamic_cast <TextFile*> (pfile))
            {
            // pfile 是 TextFile 是TextFile的派生類
            add_option("edit");
            }
            }
                細細想一下,雖然使用 dynamic_cast 確實很好地解決了我們的問題,但也需要我們付出代價,那就是與 typeid 相比,dynamic_cast 不是一個常量時間的操作。為了確定是否能完成強制類型轉(zhuǎn)換,dynamic_cast`必須在運行時進行一些轉(zhuǎn)換細節(jié)操作。因此在使用 dynamic_cast 操作時,應(yīng)該權(quán)衡對性能的影響。

            posted on 2008-11-19 14:59 井泉 閱讀(961) 評論(1)  編輯 收藏 引用 所屬分類: C++

            評論

            # re: 如何在運行時確定對象類型(RTTI) 轉(zhuǎn)  回復(fù)  更多評論   

            很好,學(xué)習(xí)了
            2012-03-28 15:55 | kelvn
            青青草原精品99久久精品66| 国产国产成人精品久久| 免费一级做a爰片久久毛片潮| 久久99国产综合精品免费| 亚洲精品高清国产一久久| 国产精品99久久久久久宅男 | 国产99久久精品一区二区| 国产亚洲精久久久久久无码AV| 久久久精品日本一区二区三区| 武侠古典久久婷婷狼人伊人| 久久狠狠高潮亚洲精品| 国产精品久久久久乳精品爆 | 国产精品美女久久久久av爽| 武侠古典久久婷婷狼人伊人| 久久99热只有频精品8| 亚洲精品tv久久久久久久久久| 久久香综合精品久久伊人| 久久综合视频网站| 国产精品一久久香蕉国产线看| 亚洲国产精品一区二区三区久久| 久久婷婷激情综合色综合俺也去 | 亚洲国产精品无码久久青草| 久久被窝电影亚洲爽爽爽| 亚洲精品国精品久久99热一| 久久久久国色AV免费看图片| 狠狠色丁香婷婷久久综合不卡| 久久久精品人妻一区二区三区蜜桃| 久久香蕉一级毛片| a高清免费毛片久久| 无码精品久久久天天影视| 国产精品亚洲综合久久| 久久久久久国产精品无码下载 | 欧美色综合久久久久久| 久久se这里只有精品| 91精品无码久久久久久五月天| 国产精品久久午夜夜伦鲁鲁| 国内精品综合久久久40p| 久久综合亚洲鲁鲁五月天| 思思久久99热只有频精品66| 久久国内免费视频| 波多野结衣AV无码久久一区|