程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++中的運行時類型識別(RTTI)

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

編輯:C++入門知識

 

1、dynamic_cast操作符
         將基類類型的指針或引用安全的轉換為派生類類型的指針或引用。

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

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

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

測試代碼:


[cpp] 
#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; 

#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;
}

 

運行結果:


[cpp] 
D::f 
D::g 
B::ff 
------- 
D::g 
dynamic cast failed 

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的字符串,用來表示相應的類型名,但務必注意這個返回的類型名與程序中使用的相應類型名並不一定一致(往往如此,見後面的程序),這具體由編譯器的實現所決定的,標准只要求實現為每個類型返回唯一的字符串。


測試代碼:

 

 

[cpp] 
#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; 

#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;
}

結果:


[cpp] 
i,i 

1B 
1D 
prt:P1B 
1D 
1B 


i,i
f
1B
1D
prt:P1B
1D
1B
1
0
1
這裡使用的是G++,vs可能與此不同。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved