運行時類型識別(Run-time type identification , RTTI),是指在只有一個指向基類的指針或引用時,確定所指對象的准確類型的操作。其常被說成是C++的四大擴展之一(其他三個為異常、模板和名字空間)。
使用RTTI的兩種方法:
1、typeid()
第一種就像sizeof(),它看上像一個函數,但實際上它是由編譯器實現的。typeid()帶有一個參數,它可以是一個對象引用或指針,返回全局typeinfo類的常量對象的一個引用。可以用運算符“= =”和“!=”來互相比較這些對象,也可以用name()來獲得類型的名稱。如果想知道一個指針所指對象的精確類型,我們必須逆向引用這個指針。比如:
#include <typeinfo> #include <iostream> #include <cmath> using namespace std; class Shape { public : int area(float r) { float s=3.14*pow(r,2); return s; } }; int main() { Shape* shape=new Shape; cout<< typeid(*shape).name()<<endl; system("pause"); }
運行結果為:
為了保持一致性,typeid()也可以用於內部類型,所以下面的表達式結果為true:
typeid(36) == typeid(int) typeid(0) == typeid(int) int i; typeid(i) == typeid(int) typeid(&i) ==typeid(int*)
可以用typeid 檢查基本類型和非多態類型:
//可以用typeid 檢查基本類型和非多態類型: #include <typeinfo> #include <iostream> using namespace std; typedef unsigned int UINT ; int main() { cout<< typeid(UINT).name()<<endl; cout<< typeid(string).name()<<endl; system("pause"); }
運行結果如圖所示:
用typeid分析指針與引用的區別:
#include <typeinfo> #include <iostream> using namespace std; class B { public: virtual double fun() { return 0.1; } }; class D :public B { }; int main() { B *p = new D; B &r = *p; //無名對象照樣有別名 cout<<(typeid(p)==typeid(B*)); //僅指向子類中父類部分 cout<<(typeid(p)!=typeid(D*)); //而非指向整個子類對象 cout<<(typeid(r)==typeid(D)); //引用的類型卻是子類的 cout<<(typeid(*p)==typeid(D)); //間址訪問的是子類對象 cout<<(typeid(*p)!=typeid(B)); //而非父類 cout<<(typeid(&r)==typeid(B*)); //引用的地址是父類的 cout<<(typeid(&r)!=typeid(D*)); //而非子類的 system("pause"); return 0; }
運行結果:
2、dynamic_cast <type-id> (expression)
該運算符把expression轉換成type-id類型的對象。
Type-id 必須是類的指針、類的引用或者void*,不可是對象;如果 type-id 是類指針類型,那么expression也必須是一個指針,如果 type-id 是一個引用,那么 expression 也必須是一個引用。
dynamic_cast主要用於類層次間的
上行轉換和
下行轉換,還可以用於類之間的
交叉轉換。在類層次間進行上行轉換時,
dynamic_cast和
static_cast的效果是一樣的;在進行下行轉換時,dynamic_cast具有類型檢查的功能,比static_cast更安全。
#include <typeinfo> #include <iostream> using namespace std; class Shape { public: virtual void Draw() { } }; class Circle:public Shape { public: virtual void Draw() { } }; int main() { Shape* sp=new Circle; Circle* cp=dynamic_cast<Circle*>(sp); if(cp) cout<<"cast successful"<<endl;; system("pause"); }
運行結果:
如何使用RTTI:
- 先激活RTTI;
- 對象所屬類型必須是多態類族;
- 若使用dynamic_cast<>轉換一個引用,則要使用異常處理機制,因為它可能拋出 std::bad_cast異常;當使用dynamic_cast<>運算符轉換一個指針時,定要檢查結果是否為NULL
- 若使用typeid (*p)來檢索對象的類型信息,又恰碰 p == NULL時,將拋出std::bad_typeid異常;