在C/C++語言中用 (type) value(還可以采用type(value))來進行顯式類型轉換,常常又被稱為強制轉換。這種轉換的正確性完全掌握在程序員手中,傳統上強制轉換往往被過度使用,成為C++程序犯錯的一個主要根源。
為了減少強制轉換的副作用,並且在查錯時使程序員能夠快速定位(總是最值得懷疑的)強制轉換,在標准C++中新增加了4個關鍵字*_cast,用來提倡一種全新的C++顯式轉換語法:
*_cast(expression)
用於明確定義良性和適度良性的轉換,包括原來不需要采用強制轉換的自動類型轉換(包括無損的提升轉換和可能丟失信息的窄化轉換[narrowing conversion],對後者編譯器一般會提出警告)。 標准C++提倡對任何數據的類型轉換(不論是自動的還是強制的),都采用新的*_cast顯式類型轉換方法。例如:
int i = 0x7fff; long l; float f; char c; // (1)典型的非強制轉換(自動轉換) // 傳統方式: l = i; f = i; // 提倡的新方式: l = static_cast(i); f = static_cast (i); // (2)窄化轉換 // 傳統方式: // 會顯示警告信息: i = l; // 可能丟失數字 i = f; // 可能丟失信息 c = i; // 可能丟失數字 // 不顯示警告信息(但仍然難定位): i = (int)l; i = (int)f; c = (char)i; // 提倡的新方式(不會顯示警告信息,且易定位): i = static_cast (l); i = static_cast (f); c = static_cast (i);
可將(同數據類型的)常型(const)轉換為非常型、將易變(volatile)型轉換為非易變型。如果用於其他類型的轉換,一般會產生一個編譯錯誤。例如:
const int i = 0; int *pi; pi = &i; // 錯誤 pi = (int *)&i; // 被反對 pi = const_cast(&i); // 完美 long *pl = const_cast (&i); // 錯誤 volatile int k = 0; int *pk = const_cast (&k); // 正確
一種安全的向下類型轉換(downcast)操作,用於在一個類繼承層次上向下移動。
因為每個派生類的基類都只有一個,而且派生類本身又包含了幾乎所有的基類信息(private型的除外),所以向上的類型轉換(upcast)總是唯一的和比較安全的。
而一個基類往往有多個派生類,而且派生類中一般會在基類的基礎上添加了一些特有的數據和操作,所以向下的類型轉換總是多態的和不太安全的。
dynamic_cast提供了一種安全的向下類型轉換操作,只有當類型轉換是正確的並且轉換取的成功,返回值才是所需要的指針;否則它將返回0(空指針NULL),表示不是正確的類型。
例如:
class Pet { //…… }; class Dog : public Pet { //…… }; class Cat : public Pet { //…… }; Pet *pPet = new Cat; // 向上的類型轉換 Dog *pDog = dynamic_cast(pPet); // 類型錯誤,返回0(NULL) Cat *pCat = dynamic_cast (pPet); // 類型正確,返回指針 Cat *pCat = static_cast (pPet); // 正確,減少運行時的開銷
注意:dynamic_cast雖然安全,但是運行時需要一定開銷,因此不提倡大量使用這種轉換。如果你已經能夠確認轉換的正確性,則可以采用前面介紹過的(無運行時開銷的)static_cast轉換。只有當你實在無法確定轉換是否正確時,才需要采用dynamic_cast轉換。
一種最有可能出問題的最不安全的類型轉換。只是在下面的情形,才需要使用這種類型轉換:當需要使用時,所得到的東西已經不同了,為了使它能夠用於原來的目的,必須再次把它轉換回來。
例如:
const int sz = 100; // 定義數組大小,標准C++提倡用常型變量(而不是常數或符號常量宏) struct X { int a[sz]; }; // 只包含一個整數數組的結構 X x; // 定義結構變量,此時結構中的數組元素的值無意義(需要初始化) int *px = reinterpret_cast(&x); // 為了初始化,先把結構轉化為int數組 for (int *i = px; i < px + sz; i++) *i = 0; // 將每個數組元素的值初始化為0 print(reinterpret_cast (px)); // 重新轉換成結構指針,以便使用,也可以直接使用原來的標識符x,此語句相當於print(&x);
使用reinterpret_cast通常是一種不明智且不方便的編程方式。但是在必須使用時,它也是非常有用的。
在這四種強制轉換中,static_cast最常用(目前還沒有流行起來,但是被標准C++著力提倡)、dynamic_cast最重要、const_cast也有用、而reinterpret_cast則很少被使用。