標籤:
dynamic_cast是四個強制類型轉換操作符中最特殊的一個,它支援運行時識別指標或引用。
>>>>>>>>>>>編譯器的RTTI設定>>>>>>>>>>>
dynamic_cast提供RTTI(Run-Time Type Information),也就是運行時類型識別。它對編譯器有要求,需要編譯器啟動“運行時類型資訊”這一選項。當編譯器不開啟RTTI時,運行含有dynamic_cast操作符的程式時會出現一個警告:
warning C4541: “dynamic_cast”用在了帶 /GR- 的多態類型“ANIMAL”上;可能導致不可預知的行為
VS2010在預設下是開啟RTTI的,也可以自己手動去開啟或者關閉,操作如下:
視圖->方案總管
在開啟的解決方案管理器中,對著項目名稱右擊,選擇屬性
配置屬性-〉C/C++
>>>>>>>>>>>>>>>>>步入正題>>>>>>>>>>>>>>>>>>
- dynamic_cast主要用於“安全地向下轉型”
dynamic_cast用於類繼承層次間的指標或引用轉換。主要還是用於執行“安全的向下轉型(safe downcasting)”,也即是基類對象的指標或引用轉換為同一繼承層次的其他指標或引用。至於“先上轉型”(即衍生類別指標或參考型別轉換為其基類類型),本身就是安全的,儘管可以使用dynamic_cast進行轉換,但這是沒必要的, 普通的轉換已經可以達到目的,畢竟使用dynamic_cast是需要開銷的。
1 class Base 2 { 3 public: 4 Base(){}; 5 virtual void Show(){cout<<"This is Base calss";} 6 }; 7 class Derived:public Base 8 { 9 public:10 Derived(){};11 void Show(){cout<<"This is Derived class";}12 };13 int main()14 { 15 Base *base ;16 Derived *der = new Derived;17 //base = dynamic_cast<Base*>(der); //正確,但不必要。18 base = der; //先上轉換總是安全的19 base->Show(); 20 system("pause");21 }
對於“向下轉型”有兩種情況。一種是基類指標所指對象是衍生類別類型的,這種轉換是安全的;另一種是基類指標所指對象為基類類型,在這種情況下dynamic_cast在運行時做檢查,轉換失敗,返回結果為0;
#include "stdafx.h"#include<iostream>using namespace std;class Base{public: Base(){}; virtual void Show(){cout<<"This is Base calss";}};class Derived:public Base{public: Derived(){}; void Show(){cout<<"This is Derived class";}};int main(){ //這是第一種情況 Base* base = new Derived; if(Derived *der= dynamic_cast<Derived*>(base)) { cout<<"第一種情況轉換成功"<<endl; der->Show(); cout<<endl; } //這是第二種情況 Base * base1 = new Base; if(Derived *der1 = dynamic_cast<Derived*>(base1)) { cout<<"第二種情況轉換成功"<<endl; der1->Show(); } else { cout<<"第二種情況轉換失敗"<<endl; } delete(base); delete(base1); system("pause");}
運行結果:
在前面的例子中,使用了dynamic_cast將基類指標轉換為衍生類別指標,也可以使用dynamic_cast將基類引用轉換為衍生類別引用。
同樣的,引用的向上轉換總是安全的:
Derived c; Derived & der2= c; Base & base2= dynamic_cast<Base&>(der2);//向上轉換,安全 base2.Show();
所以,在引用上,dynamic_cast依舊是常用於“安全的向下轉型”。與指標一樣,引用的向下轉型也可以分為兩種情況,與指標不同的是,並不存在Null 參考,所以引用的dynamic_cast檢測失敗時會拋出一個bad_cast異常:
int main(){ //第一種情況,轉換成功 Derived b ; Base &base1= b; Derived &der1 = dynamic_cast<Derived&>(base1); cout<<"第一種情況:"; der1.Show(); cout<<endl; //第二種情況 Base a ; Base &base = a ; cout<<"第二種情況:"; try{ Derived & der = dynamic_cast<Derived&>(base); } catch(bad_cast) { cout<<"轉化失敗,拋出bad_cast異常"<<endl; } system("pause");}
運行結果:
- 使用dynamic_cast轉換的Base類至少帶有一個虛函數
當一個類中擁有至少一個虛函數的時候,編譯器會為該類構建出一個虛函數表(virtual method table),虛函數表記錄了虛函數的地址。如果該類派生了其他子類,且子類定義並實現了基類的虛函數,那麼虛函數表會將該函數指向新的地址。虛表是C++多態實現的一個重要手段,也是dynamic_cast操作符轉換能夠進行的前提條件。當類沒有虛函數表的時候(也即一個虛函數都沒有定義),dynamic_cast無法使用RTTI,不能通過編譯(個人猜想...有待驗證)。
當然,虛函數表的建立對效率是有一定影響的,構建虛函數表、由表查詢函數 都需要時間和空間上的消耗。所以,除了必須聲明virtual(對於一個多態基類而言),不要輕易使用virtual函數。對於虛函數的進一步瞭解,可以查看《Effective C++》
條款07:為多態基類聲明virtual解構函式。
C++強制類型轉換操作符 dynamic_cast