相比於C++風格類型的轉換,C風格的類型轉換太過粗暴,允許你在任何類型之間進行轉換。
1.例如把一個指向 const 對象的指針轉換成指向非 const 對象的 指針(即一個僅僅去除 const 的類型轉換),把一個指向基類的指針轉換成指向子類的指針(即完全改變對象類型)。傳統的C風格的類型轉換不對上述兩種轉換進行區分。
2.C風格的類型轉換在程序語句中難以識別。在語法上,類型轉換由圓括號和標識符組成,而這些可以用在C++中的任何地方。人工閱讀很可能忽略了類型轉換的語句。
C++通過引進四個新的類型轉換操作符克服了 C 風格類型轉換的缺點,這四個操作符是, static_cast
, const_cast
, dynamic_cast
, 和 reinterpret_cast
static_cast
假設你想把一個 int 轉換成 double,以便讓包含 int 類型變量的表達式產生出浮點數值的結果。如果用 C 風格的類型轉換,你能這樣寫:
int firstNumber, secondNumber;
double result = ((double)firstNumber)/secondNumber;
如果用上述新的類型轉換方法,你應該這樣寫:
double result = static_cast<double>(firstNumber)/secondNumber;
const_cast
用於類型轉換掉表達式的 const 或 volatileness 屬性。通過使用 const_cast,你向人們和編譯器強調你通 過類型轉換想做的只是改變一些東西的 constness 或者 volatileness 屬性。這個含義被編譯器所約束。如果你試圖使用const_cast來完成修改constness 或者volatileness 屬性之外的事情,你的類型轉換將被拒絕。
比如:
class Widget { ... };
class SpecialWidget: public Widget { ... };
void update(SpecialWidget *psw);
SpecialWidget sw; // sw 是一個非 const 對象。
const SpecialWidget& csw = sw; // csw 是 sw 的一個引用
// 它是一個 const 對象
update(&csw); // 錯誤!不能傳遞一個 const SpecialWidget* 變量 給一個處理 SpecialWidget*類型變量的函數
update(const_cast<SpecialWidget*>(&csw)); // 正確,csw 的 const 被顯示地轉換掉( // csw 和 sw 兩個變量值在 update //函數中能被更新)
update((SpecialWidget*)&csw); // 同上,但用了一個更難識別 //的 C 風格的類型轉換 Widget *pw = new SpecialWidget;
update(pw); // 錯誤!pw 的類型是 Widget*,但是 update 函數處理的是 SpecialWidget*類型
update(const_cast<SpecialWidget*>(pw)); // 錯誤!const_cast 僅能被用在影響constness or volatileness 的地方上,不能用在向繼承子類進行類型轉換。
dynamic_cast
用於安全地沿着類的繼承關係向下進行類型轉換。這就是說,你能用dynamic_cast
把指向基類的指針或引用轉換成指向其派生類或其兄弟類的指針或引用,而且你能知道轉換是否成功。失敗的轉換將返回空指針(當對指針進行類型轉換時)或者拋出異常(當對引用進行類型轉換時)
比如:
Widget *pw;
...
update(dynamic_cast<SpecialWidget*>(pw));
// 正確,傳遞給 update 函數一個指針
// 是指向變量類型爲 SpecialWidget 的 pw 的指針
// 如果 pw 確實指向一個對象,
// 否則傳遞過去的將使空指針。
void updateViaRef(SpecialWidget& rsw);
updateViaRef(dynamic_cast<SpecialWidget&>(*pw));
//正確。 傳遞給 updateViaRef 函數
// SpecialWidget pw 指針,如果 pw
// 確實指向了某個對象
// 否則將拋出異常
dynamic_casts
在幫助你瀏覽繼承層次上是有限制的。它不能被用於缺乏虛函數的類型上
比如:
這是因爲int和double之間沒有繼承關係。
reinterpret_cast
reinterpret_casts
的最普通的用途就是在函數指針類型之間進行轉換。例如,假設你有一個函數指針數組:
typedef void (*FuncPtr)(); // FuncPtr is 一個指向函數的指針,該函數沒有參數返回值類型爲 void
FuncPtr funcPtrArray[10]; // funcPtrArray 是一個能容納10個FuncPtrs 指針的數組
假設你希望(因爲某些莫名其妙的原因)把一個指向下面函數的指針存入funcPtrArray數組:
int doSomething();
你不能不經過類型轉換而直接去做,因爲 doSomething 函數對於 funcPtrArray 數組來說有一個錯誤的類型。在 FuncPtrArray數組裏的函數返回值是void類型,而 doSomething函數返回值是 int 類型。
reinterpret_cast可以讓你迫使編譯器以你的方法去看待它們:
但是要注意:
轉換函數指針的代碼是不可移植的,在一些情況下這樣的轉換會產生不正確的結果,所以你應該避免轉換函數指針類型。