C 的RTTI和dynamic cast效率問題

2021-06-16 18:20:58 字數 2982 閱讀 7319

在網上經常看到有人說,dynamic_cast的效率問題.當然因為它是執行 時的cast,開銷必然少不了.

對於down cast,可以用static_cast代替,只不過不太安全.

對於鑽石結構類關係,要cast到兄弟類,那麼只能用dynamic_cast了.

記得我在做前乙個專案中,發現召喚了500個一樣的怪物的時候客戶端巨卡,於是把可以優化的地方都搞了一遍,包括把dynamic_cast改為 static_cast.最後問題解決了,這也讓我對dynamic_cast有了實踐性的感知,而不是停留在道聽途說的那種認識.

今天跟同事討論dynamic_cast,同時我也覺得gamebryo的niiskindof和nidynamiccast的效率跟c++的效率 差不多,都是執行時的型別判斷和轉換,但是同事跟我說,c++的dynamic_cast會比較虛函式表,也就是一層一層匹配v-table,開銷巨大, 而gamebryo的rtti沒有這麼大的開銷.我帶著疑問做了測試發現如下結果:

在相同的軟體和硬體環境下,相同的迴圈次數下,並且都是release版本:

1.typeid() 型別判斷與niiskindof的比較

typeid用了9秒多,niiskindof用了2秒多.

2.dynamic_cast與nidyanmiccast:

dymaic_cast用了26.7秒,nidyamiccast用了3.3秒, 8倍!

看到以上結果,我頓時大吃一驚,明白了為什麼很多引擎用自己實現的rtti而不用c++的.比如nebula引擎也有類似的rtti,當時我看到了還很不 理解.

實踐是檢驗真理的唯一標準,呵呵,以前不管別人怎麼說,我是帶有不確定的疑問,"真的是這樣嗎",今天測了才知道確實不一樣.

突然想起來,這個測試可能不准,因為編譯模式裡面把c++內建的rtti關掉了,會不會影響效率呢.有待驗證..

另我對於gamebryo或者其他類似的rtti的看法,

第一,**觀,為了方便把巨集丟到類宣告裡面,巨集本身我就覺得**,如果放在邏輯執行塊裡面我還勉強能接受,放在類宣告裡面,至少我肯定不會這麼做的,呵 呵.

第二,更重要的,effective c++上說,盡量避免dyamic_cast,不光是執行時的開銷,而且對於設計,也不太好.用到dynamic_cast的設計,不能算是好的設計.應 該在物件抽象上做好統一的介面.因為iskindof或者dynamic_cast都是依賴於具體型別的,面向過程的,相當於乙個if else,而不是物件導向的.

如何在執行時確定物件型別(rtti)

rtti 是「runtime type information」的縮寫,意思是:執行時型別資訊。它提供了執行時確定物件型別的方法。本文將簡略介紹 rtti 的一些背景知識、描述 rtti 的概念,並通過具體例子和**介紹什麼時候使用以及如何使用 rtti;本文還將詳細描述兩個重要的 rtti 運算子的使用方法,它們是 typeid 和 dynamic_cast。

其實,rtti 在c++中並不是什麼新的東西,它早在十多年以前就已經出現了。但是大多數開發人員,包括許多高層次的c++程式設計師對它並不怎麼熟悉,更不用說使用 rtti 來設計和編寫應用程式了。

一些物件導向專家在傳播自己的設計理念時,大多都主張在設計和開發中明智地使用虛擬成員函式,而不用 rtti 機制。但是,在很多情況下,虛函式無法克服本身的侷限。每每涉及到處理異類容器和根基類層次(如 mfc)時,不可避免要對物件型別進行動態判斷,也就是動態型別的偵測。如何確定物件的動態型別呢?答案是使用內建的 rtti 中的運算子:typeid 和 dynamic_cast。

首先讓我們來設計乙個類層次,假設我們建立了某個處理檔案的抽象基類。它宣告下列純虛函式:open()、close()、read()和 write():

class file

;

現在從 file 類派生的類要實現基類的純虛函式,同時還要提供一些其他的操作。假設派生類為 diskfile,除了實現基類的純虛函式外,還要實現自己的flush()和defragment()操作:
class diskfile: public file

;class mediafile: public diskfile

;

我們之所以要建立這樣的類層次,是因為這樣做以後可以建立多型物件,如:
file *pfile; // *pfile的靜態型別是 file

if(some_condition)

pfile = new textfile; // 動態型別是 textfile

else#include // typeid 需要的標頭檔案

void menu::build(const file * pfile)

else if (typeid(*pfile)==typeid(mediafile))

void menu::build(const file * pfile)

}

唉,這種做法真是顯得太業餘了,以後每次新增新的類,毫無疑問都必須打類似的補丁。顯然,這不是乙個理想的解決方案。這個時候我們就要用到 dynamic_cast,這個運算子用於多型程式設計中保證在執行時發生正確的轉換(即編譯器無法驗證是否發生正確的轉換)。用它來確定某個物件是 mediafile 物件還是它的派生類物件。dynamic_cast 常用於從多型程式設計基類指標向派生類指標的向下型別轉換。它有兩個引數:乙個是型別名;另乙個是多型物件的指標或引用。其功能是在執行時將物件強制轉換為目 標型別並返回布林型結果。也就是說,如果該函式成功地並且是動態的將 *pfile 強制轉換為 mediafile,那麼 pfile的動態型別是 mediafile 或者是它的派生類。否則,pfile 則為其它的型別:
void menu::build(const file * pfile)

else if (dynamic_cast (pfile))

}

細細想一下,雖然使用 dynamic_cast 確實很好地解決了我們的問題,但也需要我們付出代價,那就是與 typeid 相比,dynamic_cast 不是乙個常量時間的操作。為了確定是否能完成強制型別轉換,dynamic_cast`必須在執行時進行一些轉換細節操作。因此在使用 dynamic_cast 操作時,應該權衡對效能的影響。

RTTI和物件轉型

這是我學習基於linux c 做的筆記!rtti 物件轉型模板 dynamic cast 動態轉型 類型別指標或引用的轉型 static cast 靜態轉型 reinterpret cast 復詮轉型 const cast 常亮轉型 type info類 編譯器實現的動態形式資訊型別 用於在程式執行...

C 的 RTTI 可以刪掉了

一兩年沒碰程式設計了,最近開始寫乙個程式,寫的過程中想到了一些東西。看這段 這個乙個用模板實現的協議類,擁有乙個虛成員函式和乙個虛析構函式,其功能可以用以下 來測試 和協議類有點不同,這裡的模板協議類語義上並不是指標,是不是省心很多?有了新標準的move語意的話,效能上也不會有什麼問題。這只是個很簡...

C 中的RTTI機制詳解

前言 rtti是 runtime type information 的縮寫,意思是執行時型別資訊,它提供了執行時確定物件型別的方法。rtti並不是什麼新的東西,很早就有了這個技術,但是,在實際應用中使用的比較少而已。而我這裡就是對rtti進行總結,今天我沒有用到,並不代表這個東西沒用。學無止境,先從...