1. 程式人生 > >C++ 四種類型轉換操作符

C++ 四種類型轉換操作符

一、C風格型別轉換操作符

(type) expression

例子:

int firstNumber, secondNumber;
double result = ((double)firstNumber)/secondNumber;


二、C++型別轉換操作符

1.static_cast  在功能上基本上與 C 風格的型別轉換一樣強大,含義也一樣。

double result = static_cast<double>(firstNumber)/secondNumber;

它也有功能上限制。例如,你不能用 static_cast 象用 C 風格的型別轉換一樣把 struct 轉換成 int 型別或者把 double 型別轉換成指標型別,另外,static_cast 不能從表示式中去除 const 屬性,因為另一個新的型別轉換操作符 const_cast 有這樣的功能。

2.const_cast 用於型別轉換掉表示式的 const 或 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 的地方上。,
 // 不能用在向繼承子類進行型別轉換。

顯然,const_cast 最常見的用途就是將某個物件的常量性去除掉。

3.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 在幫助你瀏覽繼承層次上是有限制的。它不能被用於缺乏虛擬函式的型別上(參見條款 M24),也不能用它來轉換掉 constness。
int firstNumber, secondNumber;
double result = dynamic_cast<double>(firstNumber)/secondNumber;
 // 錯誤!沒有繼承關係

const SpecialWidget sw;
update(dynamic_cast<SpecialWidget*>(&sw));
 // 錯誤! dynamic_cast 不能轉換掉 const。
4.reinterpret_cast 的轉換結果幾乎都是執行期定義( implementation-defined 。 因 此 ,使用reinterpret_casts 的程式碼很難移植。reinterpret_casts 的最普通的用途就是在函式指標型別之間進行轉換。

例如,假設你有一個函式指標陣列:

typedef void (*FuncPtr)(); // FuncPtr is 一個指向函式的指標,該函式沒有引數,返回值型別為 void
FuncPtr funcPtrArray[10]; // funcPtrArray 是一個能容納10 個 FuncPtrs 指標的陣列
讓我們假設你希望(因為某些莫名其妙的原因)把一個指向下面函式的指標存入funcPtrArray 陣列:int doSomething();
你不能不經過型別轉換而直接去做,因為 doSomething 函式對於 funcPtrArray 陣列來說有一個錯誤的型別。在 FuncPtrArray 數組裡的函式返回值是 void 型別,而 doSomething 函式返回值是 int 型別。
funcPtrArray[0] = &doSomething; // 錯誤!型別不匹配
reinterpret_cast 可以讓你迫使編譯器以你的方法去看待它們:
funcPtrArray[0] = // this compiles
 reinterpret_cast<FuncPtr>(&doSomething);

轉換函式指標的程式碼是不可移植的(C++不保證所有的函式指標都被用一樣的方法表示),在一些情況下這樣的轉換會產生不正確的結果(參見條款 M31),所以你應該避免轉換函式指標型別。

三、總結

總結一下就是:

static_cast 和 C 風格的強制型別轉換類似,除了不能把struct轉換為int、double轉化為指標型別這樣;

const_cast 用於改變const和volatileness屬性,常見的是去掉const屬性(把const物件轉為非const);

dynamic_cast 用於類繼承關係的向下轉換,但不能用於缺乏虛擬函式的型別;

reinterpret_cast 的轉換結果是執行期定義的。

參考:More Effective C++ 條款2:儘量使用C++風格的型別轉換