18.2 運行時類型識別
通過運行時類型識別(RTTI),程序能夠使用基類的指針或引用來檢索這些指針或引用所指對象的實際派生類型。
通過下面兩個操作符提供RTTI:
(1) typeid操作符,返回指針或引用所指對象的實際類型。
(2) dynamic_cast操作符,將基類類型的指針或引用安全地轉換為派生類型的指針或引用。
這些操作符只為帶有一個或多個虛函數的類返回動態類型信息,對於其他類型,返回靜態(即編譯時)類型的信息。
對於帶虛函數的類,在運行時執行RTTI操作符,但對於其他類型,在編譯時計算RTTI操作符。
從基類指針獲得派生類型為最好的方法是通過虛函數。當使用虛函數的時候,編譯器自動根據對象的實際類型選擇正確的函數。
使用動態強制類型轉換要小心。只要有可能,定義和使用虛函數比直接接管類型管理好得多。
18.2.1 dynamic_cast操作符
可以使用dynamic_cast操作符將基類類型對象的引用或指針轉換為同一繼承層次中其他類型的引用或指針。與dynamic_cast一起使用的指針必須是有效的——它必須為0或者指向一個對象。
與其他強制類型轉換不同,dynamic_cast涉及運行時類型檢查。如果綁定到引用或指針的對象不是目標類型對象,則dynamic_cast失敗。如果轉換到指針類型的dynamic_cast失敗,則dynamic_cast的結果是0值;如果轉換到引用類型的dynamic_cast失敗,則拋出一個bad_cast類型的異常。
因此,dynamic_cast操作符一次執行兩個操作。它首先驗證被請求的轉換是否有效,只有轉換有效,操作符才實際進行轉換。一般而言,引用或指針所綁定的對象的類型在編譯時是未知的,基類的指針可以賦值為指向派生類對象,同樣,基類的引用也可以用派生類對象初始化,因此,dynamic_cast操作符執行的驗證必須在運行時進行。
1. 使用dynamic_cast操作符
可以對值為0的指針應用dynamic_cast,這樣做的結果是0。
繼承不代表有多態性,繼承只是多態性的一個前提條件。
dynamic_cast需要具有多態性的類才能進行轉換。virtual function是保證多態性的條件。
如果沒有virtual,即使是有繼承關系的類型之間,也不能使用dynamic_cast進行轉換。VS報出的編譯錯誤很直接的:type is not polymorphic
Base1 *ba=new Child1();
Child1 *c=dynamic_cast<Child1*>(ba);
Base1 *ba=new Child1();
Child1 *c=dynamic_cast<Child1*>(ba); class Base1{
public:
virtual void Method1(){}
};
class Child1:public Base1{
public:
virtual void Method1(){}
};
class Base1{
public:
virtual void Method1(){}
};
class Child1:public Base1{
public:
virtual void Method1(){}
};2. 使用dynamic_cast和引用類型
也可以使用dynamic_cast將基類引用轉換為派生類引用。
因為不存在空引用,所以不可能使用用於指針強制類型轉換的檢查策略,相反,當轉換失敗的時候,它拋出一個std::bad_cast異常,該異常在庫頭文件typeinfo中定義。
Child1 ba=Child1();
Base1 &b=ba;
try{
Child1 &c=dynamic_cast<Child1&>(b);
}
catch(bad_cast){
}
摘自 xufei96的專欄