C++面試題之 static_cast和dynamic_cast區別

在C++標準中,提供了關於類型層次轉換中的兩個關鍵字static_cast和dynamic_cast。

一、static_cast關鍵字(編譯時類型檢查)

用法:static_cast < type-id > ( expression ),該運算符把expression轉換爲type-id類型,但沒有運行時類型檢查來保證轉換的安全性,它主要有如下幾種用法:

(1)用於基本數據類型之間的轉換,如把int轉換爲char,把int轉換成enum,但這種轉換的安全性需要開發者自己保證(這可以理解爲保證數據的精度,即程序員能不能保證自己想要的程序安全),如在把int轉換爲char時,如果char沒有足夠的比特位來存放int的值(int>127或int<-127時),那麼static_cast所做的只是簡單的截斷,及簡單地把int的低8位複製到char的8位中,並直接拋棄高位。

(2)把空指針轉換成目標類型的空指針

(3)把任何類型的表達式類型轉換成void類型

(4)用於類層次結構中父類和子類之間指針和引用的轉換。

對於以上第(4)點,存在兩種形式的轉換,即上行轉換(子類到父類)和下行轉換(父類到子類)。對於static_cast,上行轉換時安全的,而下行轉換時不安全的,爲什麼呢?因爲static_cast的轉換時粗暴的,它僅根據類型轉換語句中提供的信息(尖括號中的類型)來進行轉換,這種轉換方式對於上行轉換,由於子類總是包含父類的所有數據成員和函數成員,因此從子類轉換到父類的指針對象可以沒有任何顧慮的訪問其(指父類)的成員。而對於下行轉換爲什麼不安全,是因爲static_cast只是在編譯時進行類型堅持,沒有運行時的類型檢查,具體原理在dynamic_cast中說明。

二、dynamic_cast關鍵字(運行時類型檢查)

用法:同static_cast

dynamic_cast主要用於類層次結構中父類和子類之間指針和引用的轉換,由於具有運行時類型檢查,因此可以保證下行轉換的安全性,何爲安全性?即轉換成功就返回轉換後的正確類型指針,如果轉換失敗,則返回NULL,之所以說static_cast在下行轉換時不安全,是因爲即使轉換失敗,它也不返回NULL。

對於上行轉換,dynamic_cast和static_cast是一樣的。

對於下行轉換,說到下行轉換,有一點需要了解的是在C++中,一般是可以用父類指針指向一個子類對象,如parent* P1 = new Children(); 但這個指針只能訪問父類定義的數據成員和函數,這是C++中的靜態聯翩,但一般不定義指向父類對象的子類類型指針,如Children* P1 = new parent;這種定義方法不符合生活習慣,在程序設計上也很麻煩。這就解釋了也說明了,在上行轉換中,static_cast和dynamic_cast效果是一樣的,而且都比較安全,因爲向上轉換的對象一般是指向子類對象的子類類型指針;而在下行轉換中,由於可以定義就不同了指向子類對象的父類類型指針,同時static_cast只在編譯時進行類型檢查,而dynamic_cast是運行時類型檢查,則需要視情況而定。下面通過代碼進行說明


class Base
{
    virtual void fun(){}
};
 
class Derived:public Base
{
};
由於需要進行向下轉換,因此需要定義一個父類類型的指針Base *P,但是由於子類繼承與父類,父類指針可以指向父類對象,也可以指向子類對象,這就是重點所在。如果 P指向的確實是子類對象,則dynamic_cast和static_cast都可以轉換成功,如下所示:
Base *P = new Derived();
Derived *pd1 = static_cast<Derived *>(P);
Derived *pd2 = dynamic_cast<Derived *>(P);
以上轉換都能成功。
但是,如果 P 指向的不是子類對象,而是父類對象,如下所示:

Base *P = new Base;
Derived *pd3 = static_cast<Derived *>(P);
Derived *pd4 = dynamic_cast<Derived *>(P);
在以上轉換中,static_cast轉換在編譯時不會報錯,也可以返回一個子類對象指針(假想),但是這樣是不安全的,在運行時可能會有問題,因爲子類中包含父類中沒有的數據和函數成員,這裏需要理解轉換的字面意思,轉換是什麼?轉換就是把對象從一種類型轉換到另一種類型,如果這時用 pd3 去訪問子類中有但父類中沒有的成員,就會出現訪問越界的錯誤,導致程序崩潰。而dynamic_cast由於具有運行時類型檢查功能,它能檢查P的類型,由於上述轉換是不合理的,所以它返回NULL。

三、總結

C++中層次類型轉換中無非兩種:上行轉換和下行轉換

對於上行轉換,static_cast和dynamic_cast效果一樣,都安全;

對於下行轉換:你必須確定要轉換的數據確實是目標類型的數據,即需要注意要轉換的父類類型指針是否真的指向子類對象,如果是,static_cast和dynamic_cast都能成功;如果不是static_cast能返回,但是不安全,可能會出現訪問越界錯誤,而dynamic_cast在運行時類型檢查過程中,判定該過程不能轉換,返回NULL。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章