運行時動態類型的識別其實應該是多態方面的知識,這裏我直接拿來單獨成章。ios
static_cast < Type-id > ( expression )
該運算符把expression轉換爲type-id類型,但沒有運行時類型檢查來保證轉換的安全性。它主要可用於如下幾種狀況:express
(1)用於類層次結構中基類和派生類之間指針或引用的轉換。進行上行轉換(把派生類的指針或引用轉換成基類表示)是安全的;進行下行轉換(把基類指針或引用轉換成派生類表示)時,因爲沒有動態類型檢查,因此是不安全的。
(2)用於基本數據類型之間的轉換,如把int轉換成char,把int轉換成enum。這種轉換的安全性也要開發人員來保證。
(3)把空指針轉換成目標類型的空指針(不安全!!)。
(4)把任何類型的表達式轉換成void類型。
安全
class Base { }; class Derived:public Base {}; int main() { Base b; Derived* pD = &b; //error C2440: 「初始化」: 沒法從「Base *」轉換爲「Derived *」 pD = static_cast<Derived*> (&b); return 0; }
在上面代碼中pD做爲一派生類指針,將它指向基類是錯誤的(但反過來是能夠的)。函數
能夠用static_cast將基類指針強制轉換爲派生類指針,這樣即可以將pD指向基類對象。spa
但像上面這樣使用static_cast進行向上映射時,是至關危險的,可能會形成沒法跟蹤的運行期錯誤。
指針
C++提供了dynamic_cast操做符,能夠在運行期間檢測類型轉換是否安全。dynamic_cast和static_cast有一樣的語法:
code
dynamic_cast < Type-id > ( expression )
The dynamic_cast operator in C++ is used for downcasting a reference or pointer to a more specific type in the class hierarchy. Unlike the static_cast, the target of the dynamic_cast must be a pointer or reference to class.
Type-id必須是一個類的的指針或引用,也能夠是 void *,參數expression必須是一個能獲得一個指針或者引用的表達式。
對象
同時,dynamic_cast僅對多態類型有效,也就是說使用dynamic_cast時要求基類中要有虛函數,不然會有編譯錯誤;blog
而static_cast則沒有這個限制。另外dynamic_cast要求轉型的目的類型必須是指針或者引用。這是因爲運行時類型檢查須要運行時類型信息,而這個信息存儲在類的虛函數表中,只有定義了虛函數的類纔有虛函數表,沒有定義虛函數的類是沒有虛函數表的。ci
例:
class Base { public: void fun( ) {}; }; class Derived:public Base { }; int main( ) { Base b; Derived d; Base *pb = &b; Derived *pd1 = static_cast<Derived *> (pb); Derived *pd2 = dynamic_cast<Derived *>(pb); // error C2683: 「dynamic_cast」:「Base」不是多態類型 return 0; }
若將fun()函數聲明爲虛函數,則不會有上面的錯誤。
若是pb實際指向一個 Derived類型的對象,pd1和pd2是同樣的,而且這兩個指針執行Derived類型的任何操做都是安全的;若是pb實際指向的是一個Base類型的對象,那麼pd1將是一個指向該對象的指針,對它進行Derived類型的操做將是不安全的,而pd2將會獲得一個空指針(即0,由於dynamic_cast失敗)!
例:
#include <iostream> using namespace std; class Base { public: virtual void fun1() { cout << "Base::fun1()" << endl; } virtual ~Base() { } }; class Derived1: public Base { public: virtual void fun1() { cout << "Derived1::fun1()" << endl; } virtual void fun2() { cout << "Derived1::fun2()" << endl; } }; class Derived2: public Derived1 { public: virtual void fun1() { cout << "Derived2::fun1()" << endl; } virtual void fun2() { cout << "Derived2::fun2()" << endl; } }; void fun(Base *b) { b->fun1(); //嘗試將b轉換爲Derived1指針 Derived1 *d = dynamic_cast<Derived1 *>(b); //判斷轉換是否成功 if (d != 0) d->fun2(); } int main() { Base b; fun(&b); Derived1 d1; fun(&d1); Derived2 d2; fun(&d2); return 0; }
運行結果:
Base::fun1()
Derived1::fun1()
Derived1::fun2()
Derived2::fun1()
Derived2::fun2()
typeid語法形式:
typeid ( 表達式 )
typeid ( 類型說明符 )
typeid功能
得到表達式或類型說明符的類型信息,表達式有多態類型時,會被求值,並獲得動態類型信息;不然,表達式不被求值,只能獲得靜態的類型信息。
類型信息用type_info對象表示,type_info是typeinfo頭文件中聲明的類;
typeid的結果是type_info類型的常引用;
能夠用type_info的重載的「==」、「!=」操做符比較兩類型的異同;
type_info的name成員函數返回類型名稱,類型爲const char *。
#include <iostream> #include <typeinfo> using namespace std; class Base { public: virtual ~Base() { } }; class Derived: public Base { }; void fun(Base *b) { const type_info &info1 = typeid(b); const type_info &info2 = typeid(*b); cout<<"typeid(b): "<<info1.name ()<<endl; cout<<"typeid(*b): "<<info2.name ()<<endl; if(info2 == typeid(Base)) cout<<"A base class!"<<endl; else cout<<"A Derived class!"<<endl; cout<<endl; } int main() { Base b; fun(&b); Derived d; fun(&d); return 0; }
運行結果:
typeid(b): P4Basetypeid(*b): 4BaseA base class!typeid(b): P4Basetypeid(*b): 7DerivedA Derived class!