c++ 引入了 const_cast, reinterpret_cast 之類的新的顯式型別轉換方式,不僅大多數 c 程式設計師覺得不是很習慣,就連某些有經驗的c++ 程式設計師都會在一些細節上犯錯。誠然,既然我們可以簡單的寫出:
int i = (int)p;// p is a pointer
這樣的顯式轉換,為什麼還要使用
int i = reinterpret_cast( p );
這麼複雜的形式呢?
這篇文章的目的是簡單介紹 c++ 的型別轉換系統,並對使用和擴充套件進行一些討論。
1. 為什麼需要型別轉換?
型別轉換被用來把乙個型別的值轉換成另乙個型別。類似於 c++ 這樣的程式語言是強型別的,因此每乙個值都有它相應的型別。當你需要把乙個值轉換為另乙個型別時,你需要使用下列方式中的一種:隱式轉換,顯式轉換和無法轉換。假設我們使用老式的顯式轉換:
char c = 'a';
int* p = null;
int a = c;// 隱式轉換
a=(int) p; // 顯式轉換
double d=(double) p;// 無法轉換
通常,隱式轉換意味著編譯器認為你的轉換是合理的或者是安全的;顯式轉換意味著編譯器能夠找到乙個轉換方式,但是它不保證這個轉換是否安全,所以需要程式設計師額外指出;而無法轉換則意味著編譯器無法發現一條直接的路徑來進行型別轉換。
2. 為什麼需要 c++ 風格的顯式轉換?
c++ 風格的顯式轉換為我們提供了更精確的語義和對其進一步擴充套件的可能。在 c 語言中,我們可以用乙個簡單的 (int*) 來完成下面的轉換:
const char* s = 0;
int* p = (int*) s;
這一句語句,不僅轉換了型別,還把 const 也去掉了。通常如果我們看到一句游離的顯式轉換,我們不能立即知道作者的意圖,這也為今後的錯誤埋下了伏筆。c++ 風格的現實轉換通過區分各種轉換情況來增加安全性:通過 const_cast 來取消 const、volatile 之類的修飾,通過 static_cast 來做相關型別的轉換,通過 reinterpret_cast 來做低階的轉換,...。有乙個例子可以說明這些轉換的「精確」程度:
class inte***ce;
class base {};
class derived : public inte***ce, public base {};
int main()
這段**中,兩個 cast 都是合法的,但是意義不同。前者意味著「把 b 的指標的值直接賦給 d1,並且把它作為 derived 型別解釋」,後者意味著「根據相關型別資訊來做轉換,如果可能,對 b 指標做一些偏移」。在上面這個例子裡面,d1 和 d2 是不相等的!可能由於很多書上都說:如果你要在指標之間互相轉換,應該使用 reinterpret_cast,所以不少程式設計師使用 reinterpret_cast 來做一切指標型別轉換,雖然通常他們不會得到錯誤,但是的確是不小的隱患。
3. 一些例子
(1) itf_cast
在 *** 中,如果我有乙個指向 ihtmldocument 的介面指標,並且我想從中獲得乙個 ipersistfile 的指標,我們可以用下述**:
ipersistfile* ppersistfile;
if( failed( phtmldocument->queryinte***ce(iid_ipersistfile, (lpvoid*) &ppersistfile) ) )
throw something;
這段**很簡單但是不夠直接,所以我們可以實現這樣乙個函式:
template
t1 itf_cast(t2 v2)
然後我們可以把上面的語句寫成
ppersistfile = itf_cast( phtmldocument );
這非常的直觀。仔細的讀者可能會發現 __uuidof 不是標準的 c++ 所定義的,而是 vc 的乙個擴充套件。事實上,在這裡你可以用 traits 很簡單的實現同樣的功能。
(2) stream_cast
有時候,我們經常會遇到一些自定義型別之間轉換問題,譬如說 std::string 和 double,甚至 std::string 和 rect 之類的轉換。如果參與轉換的兩個型別都定義了輸入輸出運算(精確的說,源型別支援輸出運算,目的型別支援輸入運算),那麼我們可以用以下的方式來進行轉換:
template
t1 stream_cast(const t2& v2)
這樣一來,你可以用以下語句進行轉換:
string s("0.5");
double d = stream_cast( s );
(3) safe_cast
有時候我們希望我們的顯式轉換是安全的,這裡安全的定義是,這個值在兩個型別中德表示都是無損的。也就是說,(t2)(t1)v1 == v1。那我們可以定義這樣的顯式轉換:
template
t1 stream_cast(const t2& v2)
於是,stream_cast(1000); 這樣的語句就會丟擲異常。
上面是我個人對於 c++ 風格的顯式型別轉換的一些理解和看法,希望有興趣的人一起討論。
C 中的顯式型別轉換
寫c 的時候,有時候不可避免的會使用型別轉換,良好的編碼風格中應該避免隱式轉換,隱式轉換有時候會產生不易察覺的問題。c 提供了四種顯示型別轉換方式,當然顯示的強制型別轉換也是需要盡量避免的。四種顯示轉換具有相同的形式 cast name expression type 是轉換的目標型別 expres...
C 顯式型別轉換
對於型別轉換,我在查資料的時候看到了一種很有意思的解釋,我們可以這樣理解型別轉換 某塊記憶體中的資料是不變的,而型別就是我們戴上的眼鏡,當我們戴上一種眼鏡後,我們就會用對應的型別來解釋記憶體中的資料,這樣不同的解釋就得到了不同的資訊。所謂強制型別轉換實際上就是換上另一副眼鏡後再來看同樣的那塊記憶體資...
c 顯式型別轉換
乙個命名的強制型別轉換具有以下形式 cast name expression 其中,type是轉換的目標型別,而expression是要轉換的值。如果type是引用型別,則結果是左值。cast name是static cast dynamic cast const cast reinterpret ...