我們在寫c++**的時候經常碰到使用dynamic_cast進行型別轉換的情況,也都知道經過dynamic_cast的轉換更加安全,因為dynamic_cast進行了型別檢查。 但是可能很多人不知道dynamic_cast是c++ 執行時型別資訊(rtti)機制鏈條上的乙個節點。 rtti提供了兩個操作符和乙個類:
整個rtti, 作為乙個整體,暴露給程式設計師的就是這三個元素。因此我們關注的焦點也就在它們身上了。
在c++中存在虛函式,也就存在了多型性,對於多型性的物件,其基類的指標可以指向任何派生類的物件,這時就有可能不知道基類指標到底指向的是哪個物件的情況,型別的確定要在執行時利用執行時型別標識做出。rtti 就是語言內建的支援執行時識別物件的型別並提供型別資訊的一套機制。
#include
#include
class person
};class employee : public person ;
int main()
輸出的結果是
int從上面的**可以看出,typeid操作符最常見的用法就是在執行時提供物件的真實型別資訊(name), 接受的可以是 乙個型別名或者乙個表示式。class employee
class employee
class person*
class employee
當輸入的是乙個指標時,typeid會識別為指標型別(class person*
而不是class person
), 但是typeid並不會把引用識別為引用,因此不會有class person&
這樣的結果。也就是說輸入引用和輸入物件對於typeid是一回事,但是對於指標你得解引用!
class account{}; //沒有虛函式非多型型別
account acc;
account& ref = acc;
std::cout
<< typeid(ref).name() << std::endl; //ok, 輸出 class account
雖然typeid支援這種非多型型別的查詢,但是這些資訊實際上在編譯時就已經知道了,因此這樣的用法更多得是為了完整性考慮,而沒有多大的實際用處。
person* ptr = null;
void* vptr = ptr;
trycatch(std::bad_typeid& e)
catch(...){}
trycatch(std::bad_typeid& e)
catch(...){}
trycatch(std::bad_typeid& e)
catch(...){}
輸出的結果是
void*上面的例子可以看到對於空指標,typeid不會深入檢查指標是否為空,而是僅僅返回指標的型別,但是解引用空指標則會引發bad_typeid異常!person*
bad_typeid caught on *ptr
const
std::type_info& tinforef = typeid( int ); //編譯通過
const
std::type_info tinfo = typeid( int ); //編譯錯誤
type_info型別具有私有的拷貝建構函式和賦值函式,因此typeid返回的引用不能被賦給type_info物件,同樣type_info也沒有公有建構函式因此不能被建立,只能通過這種引用的方式獲取它的例項!
class type_info ;
這裡的」==」判斷型別是否一樣,而不是判定兩個指標指向同乙個物件。
const std::type_info& tinforef = typeid( employee );
employee employee;
person* ptr = &employee;
if( tinforef == typeid( *ptr ) ) //判斷成立,都是employee型別
作為 rtti 三大件之一, dynamic_cast可能是最重要的了!前面我們已經講過了dynamic_cast的用法,而且也指出dynamic_cast必須是作用於多型型別,下面的**會編譯錯誤, 因為person沒有虛函式不是多型型別!
class person {};
class employee : public person {};
employee employee;
person* ptr = &employee;
employee* emp = dynamic_cast
(ptr);
關於rtti到底怎麼實現,標準沒有指出,因此不同的編譯器有不同的實現方法。這裡為了便於理解rtti的執行原理給出了乙個實現模型!
這裡編譯器在vtable裡面新增了一項type_info*指標,指向type_info結構,每個型別有乙個type_info資料段。 從這裡可以看出編譯器提供關閉rtti選項的作用了,由於編譯器需要為每個多型型別產生乙個type_info結構,關閉rtti確實可以省出不少空間!
rtti的消耗到底是多少,具體的情況肯定取決於編譯器的實現和實際的型別,比如型別名的長度等等。
visual studio 和 gcc 預設都開啟rtti支援,但是你也可以關閉該選項,在visual studio下,properties->configuration properties->c/c++->language,右面enable run-time type information選擇no(/gr-). gcc使用-fno-rtti關閉rtti支援。
此時使用dynamic_cast,typeid
都會丟擲std::__non_rtti_object
異常!顯然這是因為這時候編譯器並沒有為多型型別生成type_info
資料,而dynamic_cast,typeid
都會用到這一資訊!
需要注意的是關閉了rtti 並不一定導致執行時異常,只有在切實需要type_info資訊而rtti又關閉的時候才會丟擲異常。 比如上行轉化的時候即使使用了dynamic_cast且關閉了rtti仍然不會有問題!
執行時型別識別(RTTI)
執行時型別識別 rtti 即是程式執行過程中知道某個物件屬於某個類,我們平時用c 程式設計接觸的rtti一般是編譯器的rtti,即是在新版本的vc 編譯器裡面選用 使能rtti 然後載入typeinfo.h檔案,就可以使用乙個叫typeid 的運運算元,它的地位與在c 程式設計中的sizeof 運運...
RTTI 執行時型別識別
執行時型別識別也是面試時常問的問題,今天整理一下,作為學習和分享 在存在虛函式表的繼承關係時,每個虛函式表前面都設定有乙個type info指標,用於支援rtti,rtti是為多型而生成的資訊,包括物件繼承關係,物件本身的描述等,只有具有虛函式的物件才會生成。執行時型別識別 run time typ...
C 執行時型別識別(RTTI)
執行時型別識別rtti 即run time type identification 主要通過typeid和dynamic cast來實現 typeid操作符 type info實現如下 class type info 應用如下 typeid obj name 列印出指標obj指向的實際的物件型別if...