C++ dynamic_cast操作符
在C++中,編譯期的類型轉換有可能會在運行時出現錯誤,特別是涉及到類對象的指針或引用操作時,更容易產生錯誤。Dynamic_cast操作符則可以在運行期對可能產生問題的類型轉換進行測試。
#include<iostream> using namespace std;class base { public :void m(){cout<<"m"<<endl;} };class derived : public base { public:void f(){cout<<"f"<<endl;} };int main() {derived * p;p = new base;p = static_cast<derived *>(new base);p->m();p->f();return 0; }本例中定義了兩個類:base類和derived類,這兩個類構成繼承關系。在base類中定義了m函數,derived類中定義了f函數。在前面介紹多態時,我們一直是用基類指針指向派生類或基類對象,而本例則不同了。本例主函數中定義的是一個派生類指針,當我們將其指向一個基類對象時,這是錯誤的,會導致編譯錯誤。但是通過強制類型轉換我們可以將派生類指針指向一個基類對象,p = static_cast<derived *>(new base);語句實現的就是這樣一個功能,這樣的一種強制類型轉換時合乎C++語法規定的,但是是非常不明智的,它會帶來一定的危險。在程序中p是一個派生類對象,我們將其強制指向一個基類對象,首先通過p指針調用m函數,因為基類中包含有m函數,這一句沒有問題,之后通過p指針調用f函數。一般來講,因為p指針是一個派生類類型的指針,而派生類中擁有f函數,因此p->f();這一語句不會有問題,但是本例中p指針指向的確實基類的對象,而基類中并沒有聲明f函數,雖然p->f();這一語句雖然仍沒有語法錯誤,但是它卻產生了一個運行時的錯誤。換言之,p指針是派生類指針,這表明程序設計人員可以通過p指針調用派生類的成員函數f,但是在實際的程序設計過程中卻誤將p指針指向了一個基類對象,這就導致了一個運行期錯誤。
產生這種運行期的錯誤原因在于static_cast強制類型轉換時并不具有保證類型安全的功能,而C++提供的dynamic_cast卻能解決這一問題,dynamic_cast可以在程序運行時檢測類型轉換是否類型安全。當然dynamic_cast使用起來也是有條件的,它要求所轉換的操作數必須包含多態類類型(即至少包含一個虛函數的類)。
#include<iostream> using namespace std;class base { public :void m(){cout<<"m"<<endl;} };class derived : public base { public:void f(){cout<<"f"<<endl;} };int main() {derived * p;p = new base;p = dynamic_cast<derived *>(new base);p->m();p->f();return 0; }在本例中利用dynamic_cast進行強制類型轉換,但是因為base類中并不存在虛函數,因此p = dynamic_cast<derived *>(new base);這一句會編譯錯誤。dynamic_cast能否正確轉換與目標類型是否為多態類類型無關,dynamic_cast要求被轉換的類型必須為多態類類型。為了解決本例中的語法錯誤,我們可以將base類中的函數m聲明為虛函數,virtual void m(){cout<<"m"<<endl;}。
dynamic_cast還要求<>內部所描述的目標類型必須為指針或引用。如例3所示,如果我們將例2中的主函數換成例3的形式,這也是無法通過編譯的。
我們來看一下正確使用dynamic_cast的代碼。
#include<iostream> using namespace std;class base { public :virtual void m(){cout<<"m"<<endl;} };class derived : public base { public:void f(){cout<<"f"<<endl;} };int main() {derived * p;p = dynamic_cast<derived *>(new base);if(p){p->m();p->f(); }elsecout<<"Convert not safe!"<<endl;return 0; }在本例中通過dynamic_cast來初始化指針p,在初始化過程中dynamic_cast會檢測操作數new base轉換為目標類型derived *是否能保證類型安全,如果類型安全則將new base結果賦給p指針,否則返回0,也即false。而本例中是要用基類對象地址去初始化派生類指針,這顯然是無法保證類型安全的,因此p最后得到的返回值是0。在主函數中經過判斷語句,最終程序輸出“Convert not safe!”。
Dynamic_cast轉換有自己的規則,下面將通過示例來介紹轉換規則。
本例分別定義了兩個類:base類和derived類,這兩個類構成繼承關系,為了測試dynamic_cast轉換規則,我們在類中各自定義了一個虛函數。在本例的主函數中我們分別測試基類轉換為派生類和派生類轉換為基類時dynamic_cast轉換返回值。本例最終運行結果如下:
??? Base to Derived is error
??? Derived to Base is ok
從結果可以看出從不能將指向基類對象的指針轉換為指向派生類對象的指針,但是可以將指向派生類對象的指針轉換為指向基類對象的指針。
在本例中,定義了兩個類A和B,這兩個類不構成繼承關系,我們嘗試將指向兩個類對象的指針進行互相轉換,看程序運行結果:
??? B to A is error
??? A to B is error
從程序運行結果不難看出,任意兩個不相關的多態類類型之間的轉換也是不能進行的。
總結一下dynamic_cast轉換規則,只允許指向派生類對象的指針轉換為指向基類對象的指針。
C++提供的兩個類型轉換操作符static_cast和dynamic_cast,static_cast可以用于任何類型的強制類型轉換,但是它不保證轉換過程中的類型安全,dynamic_cast只能用于多態類類型的轉換,而且要求轉換的目的類型必須為指針或引用,并且它可以保證轉換過程中類型安全。
總結
以上是生活随笔為你收集整理的C++ dynamic_cast操作符的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++抽象基类和纯虚成员函数
- 下一篇: s3c2440移植MQTT