c++中RTTI

來源:互聯網
上載者:User

標籤: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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.