C++中的運行時類型識別(RTTI)

C++中運行時類型識別(RTTI)

 

1、dynamic_cast操作符

         將基類類型的指針或引用安全的轉換爲派生類類型的指針或引用。

注意:基類至少帶有一個虛函數,這樣源類型纔可能是多態的,纔會在運行時確定類型。否則將導致編譯錯誤。

         如果轉換成功,則返回一個指向轉換後類型的指針或引用;如果轉換失敗,指針類型的轉換結果爲0,引用類型則拋出bad_cast類型的異常。

         如果是指針類型,操作數可以是0。但是沒有空類型的引用。

測試代碼:

#include <iostream>
#include <typeinfo>

using namespace std;
class B
{
public:
    virtual void f()
    {
        cout<<"B::f"<<endl;
    }
    void ff()
    {
        cout<<"B::ff"<<endl;
    }
};

class D:public B
{
public:
    void f()
    {
        cout<<"D::f"<<endl;
    }
    void g()
    {
        cout<<"D::g"<<endl;
    }
};


void ta()
{///pointer
    B *b=0;
    D *d=0;
    b = new D();
    b->f();///D::f
    d = dynamic_cast<D*>(b);
    if(d)
    {        d->g();    }///D::g
    else
    {        b->ff();    }

    b = new B();
    d = dynamic_cast<D*>(b);
    if(d)
    {        d->g();    }
    else
    {        b->ff();    }///B::ff

}

void tb()
{
    D d;
    B c;
    B &b=d;
    try
    {
        D & dt = dynamic_cast<D&>(b);
        dt.g();
    }
    catch(bad_cast)
    {
        cout<<"dynamic cast failed"<<endl;
    }
    B &br = c;///如果這裏寫b=c;將發生奇怪的現象。
    try
    {
        D & dt = dynamic_cast<D&>(br);
        dt.g();
    }
    catch(bad_cast)
    {
        cout<<"dynamic cast failed"<<endl;
    }
}

int main()
{
    ta();
    cout<<"-------"<<endl;
    tb();
    return 0;
}

運行結果:

D::f
D::g
B::ff
-------
D::g
dynamic cast failed


2、typeid操作符

typeid的表達式:

typeid(e)

其中e可以是任意表達式或者類型名。

如果表達式的類型是類類型且該類包含至少1個虛函數,則表達式的動態類型(實際類型)可能不同於它的靜態類型。

如果操作數的不是類類型,或者是沒有虛函數的類,則typeid操作符指出操作數的靜態類型。如果操作數定義了至少一個虛函數,則在運行時計算類型。

ISO C++標準並沒有確切定義type_info,它的確切定義是編譯器相關的,但是標準卻規定了其實現必需提供如下四種操作:

t1 == t2 如果兩個對象t1和t2類型相同,則返回true;否則返回false
t1 != t2 如果兩個對象t1和t2類型不同,則返回true;否則返回false
t.name() 返回類型的C-style字符串,類型名字用系統相關的方法產生
t1.before(t2) 返回指出t1是否出現在t2之前的bool值

type_info類提供了public虛 析構函數,以使用戶能夠用其作爲基類。它的默認構造函數和拷貝構造函數及賦值操作符都定義爲private,所以不能定義或複製type_info類型的對象。程序中創建type_info對象的唯一方法是使用typeid操作符(由此可見,如果把typeid看作函數的話,其應該是type_info的 友元)。type_info的name成員函數返回C-style的字符串,用來表示相應的類型名,但務必注意這個返回的類型名與程序中使用的相應類型名並不一定一致(往往如此,見後面的程序),這具體由編譯器的實現所決定的,標準只要求實現爲每個類型返回唯一的字符串。

測試代碼:


#include <iostream>
#include <typeinfo>

using namespace std;
class B
{
public:
    virtual void f()
    {
        cout<<"B::f"<<endl;
    }
    void ff()
    {
        cout<<"B::ff"<<endl;
    }
};

class D:public B
{
public:
    void f()
    {
        cout<<"D::f"<<endl;
    }
    void g()
    {
        cout<<"D::g"<<endl;
    }
};

void tc()
{
    D d;
    B b;
    int k=0;
    cout<<typeid(k).name()<<","<<typeid(int).name()<<endl;
    cout<<typeid(float).name()<<endl;
    cout<<typeid(b).name()<<endl;
    cout<<typeid(d).name()<<endl;

    B *bp=new D();
    cout<<"prt:"<<typeid(bp).name()<<endl;//直接判斷指針,而不是指針所指向的對象的類型
    cout<<typeid(*bp).name()<<endl;
    bp = new B();
    cout<<typeid(*bp).name()<<endl;
    cout<<typeid(*bp).before(typeid(char))<<endl;
    cout<<typeid(char).before(typeid(*bp))<<endl;
    cout<<typeid(B).before(typeid(D))<<endl;
}
int main()
{
    tc();
    return 0;
}

結果:

i,i
f
1B
1D
prt:P1B
1D
1B
1
0
1

這裏使用的是G++,vs可能與此不同。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章