今天從學長那裡聽來一道騰訊的面試題,問的是C++中的dynamic_cast在什麼情況下是錯誤的?我認為這個問題的更好的描述是dynamic_cast的使用條件是什麼?
C++提供了兩種方式來支援RTTI,dynamic_cast是其中一種,另一種是typeid()。表面上看,dynamic_cast有兩種形式:
Base *pBase = new Derived();
Derived *pDerived = dynamic_cast<Derived *> pBase;
Base refBase = Derived();
Derived &refDerived = dynamic_cast<Derived &> refBase
即dynamic_cast用于将基類的引用或指針轉化為派生類的引用或指針。但使用條件是:1、基類的指針或引用确實綁定到派生類的對象上;2、隻有當基類至少含有一個虛函數的時候才能使用dynamic_cast。原因是RTTI機制依賴于虛函數表(inside C++ object model第一章給出了解釋),而dynamic_cast是RTTI的一種,是以必須要有虛函數表的支援,也就是要虛類中至少有一個虛函數。
那麼,dynamic_cast有什麼好處呢?
我們知道,基類的指針即使指向的是派生類的對象,但通過基類的指針也隻能通路到基類中包含的public成員,那如果想要通路派生類中新增的public成員呢?這就需要将基類的的指針動态類型轉化為派生類的指針。見以下代碼:
#include<iostream>
using namespace std;
class base{
public:
base(int x):a(x){ }
virtual void fcn(){ } //要有虛函數
int a;
};
class derived:public base{
public:
derived(int x,int y):base(x),b(y){ }
int b;
};
int main(){
base *pbase = new derived(100, 200);
cout << pbase->a << endl;
//cout << pbase->b << endl; //不能通過基類的指針通路派生類新增的public成員
derived *pderived = dynamic_cast<derived *>(pbase);
cout << pderived->a << endl;
cout << pderived->b << endl;
}
如何對dynamic_cast轉化是否成功進行判斷,進而選擇進行基類的操作還是進行派生類的操作呢?見下面的代碼:
#include<iostream>
using namespace std;
class base{
public:
base(int x):a(x){ }
virtual void fcn(){ } //要有虛函數
int a;
};
class derived:public base{
public:
derived(int x,int y):base(x),b(y){ }
int b;
};
int main(){
base *pbase0 = new base(100);
base *pbase1 = new derived(100, 200);
if(NULL != dynamic_cast<derived *>(pbase0)){
cout << dynamic_cast<derived *>(pbase0)->b << endl;
cout<<"derived"<<endl;
}else{
cout << pbase0->a << endl;
cout<<"base"<<endl;
}
if(derived *pderived = dynamic_cast<derived *>(pbase1)){
cout << dynamic_cast<derived *>(pbase1)->b << endl;
cout<<"derived"<<endl;
}else{
cout << pbase1->a << endl;
cout<<"base"<<endl;
}
}
運作結果如下:
100
base
200
derived
《C++ primer》第5版P731上給出了以下代碼架構:
if(Derived *dp = dynamic_cast<derived *>(bp)){
//使用bp指向的Derived對象
}else{
//使用bp指向的Base對象
}
在vs和gcc下測試過:如果bp指向的不是派生類的對象而是基類的對象的話,那麼兩種編譯器下都不能通過編譯!!!這樣的運作時動态類型判斷也就沒有意義了。這種寫法值得商榷!
如果是引用的話,當轉化不成功時會抛出std::bad_cast異常,詳見《C++ primer》第5版P731。