標籤:class 類型轉換 檔案的 logs als 相關 ast 系統 virt
RTTI 是“Runtime Type Information”的縮寫,意思是:運行時類型資訊。它提供了運行時確定物件類型的方法。本文將簡略介紹 RTTI 的一些背景知識、描述 RTTI 的概念,並通過具體例子和代碼介紹什麼時候使用以及如何使用 RTTI;本文還將詳細描述兩個重要的 RTTI 運算子的使用方法,它們是 typeid 和 dynamic_cast。如何確定對象的動態類型呢?答案是使用內建的 RTTI 中的運算子:typeid 和 dynamic_cast。
typeid的主要作用就是讓使用者知道當前的變數是什麼類型的,對於我們自訂的結構體和類,tpyeid都能支援。
typeid是C++的關鍵字之一,等同於sizeof這類的操作符。typeid操作符的返回結果是名為type_info的標準庫類型的對象的引用,它的運算式有兩種形式。
如果運算式的類型是類類型且至少包含有一個虛函數,則typeid操作符返回運算式的動態類型,需要在運行時計算;否則,typeid操作符返回運算式的靜態類型,在編譯時間就可以計算。ISO C++標準並沒有確切定義type_info,它的確切定義編譯器相關的,但是標準卻規定了其實現必需提供如下四種操作(在之後的章節中我會來分析type_info類檔案的源碼):
| t1 == t2 |
如果兩個對象t1和t2類型相同,則返回true;否則返回false |
| t1 != t2 |
如果兩個對象t1和t2類型不同,則返回true;否則返回false |
| t.name() |
傳回型別的C-style字串,類型名字用系統相關的方法產生 |
| t1.before(t2) |
返回指出t1是否出現在t2之前的bool值 |
#include <iostream>
using namespace std;
class Base {};
class Derived: public Base {};
int main()
{
Base b, *pb;
pb = NULL;
Derived d;
cout << typeid(int).name() << endl
<< typeid(unsigned).name() << endl
<< typeid(long).name() << endl
<< typeid(unsigned long).name() << endl
<< typeid(char).name() << endl
<< typeid(unsigned char).name() << endl
<< typeid(float).name() << endl
<< typeid(double).name() << endl
<< typeid(string).name() << endl
<< typeid(Base).name() << endl
<< typeid(b).name()<<endl
<< typeid(pb).name()<<endl
<< typeid(Derived).name() << endl
<< typeid(d).name()<<endl
<< typeid(type_info).name() << endl;
return 0;
}
運行結果:
dynamic_cast 操作符,將基類的指標或引用安全的轉換為衍生類別的指標或引用。
1. 原理:將一個基類對象指標(或引用)cast (拋)到繼承類指標,dynamic_cast 會根據基類指標是否真正指向繼承類指標來做相應處理。
2. 傳回值:對指標進行dynamic_cast,失敗返回null,成功返回正常cast後的對象指標;對引用進行dynamic_cast,失敗拋出一個異常,成功返回正常cast後的對象引用。
3. 注意:dynamic_cast在將父類cast到子類時,父類必須要有虛函數。
在c++中使用dynamic_cast進行類型轉換屬於向下類型,即將基類類型轉換為衍生類別類型,向上類型轉換編譯器可以自動完成。
下面的代碼說明了C++中RTTI運行機制。
#include <iostream>#include <typeinfo>using namespace std;class base{public: virtual void funA() {cout<<"Base "<<endl;}};class derived : public base{public: virtual void funB() { cout<<"derived "<<endl;}};void funcC(base* p){ derived* dp=dynamic_cast<derived*>(p); if(dp!=NULL) dp->funB(); else p->funA();}void funcD(base* p){ derived* dp=NULL; if(typeid(*p)==typeid(derived)) { dp=static_cast<derived*>(p); dp->funB(); } else p->funA();}int main(){ base *cp=new derived;//向上類型轉換,系統自動完成,指標cp指向derived中繼承base部分 cout<<typeid(cp).name()<<endl;//class base* cout<<typeid(*cp).name()<<endl;//class derived funcD(cp); //typeid(*cp)==typeid(derived),使用static_cast<derived*>(cp)也可以將基類轉換為衍生類別,是在編譯時間完成,而dynamic_cast是在運行時處理的 funcC(cp);//採用dynamic_cast完成基類到衍生類別的轉換,轉換成功 base* dp=new base; funcC(dp);//基類指標指向基類,此時採用dynamic_cast完成基類到衍生類別的轉換失敗。
funcD(dp); return 0; }
運行結果為:
class base*class derivedclass derivedclass derivedclass baseclass base
注意:基類指標或引用指向衍生類別對象的情況,此時轉換才有意義。 否則轉換就不能成功,如上面的funcC(dp)函數中derived* dp=dynamic_cast<derived*>(dp)就失敗了,返回NULL
c++中RTTI