Guru of the week:#17 型別對映. (轉)
作者:Hub Sutter
譯者:黃森堂
/*此文是譯者出於自娛翻譯的GotW(Guru of the Week)系列文章的一篇,原文的版權是屬於Hub Sutter(著名的C++專家,《Exceptional C++》的作者)。此文的翻譯沒有徵得原作者的同意,只供學習討論。——譯者:黃森堂*/
#17 型別對映.
難度:6/10
你知道C++的型別對映嗎?,在你的程式碼中使用它們來提高可靠性。
問題:
比舊的C的型別對映,在標準C++中新的型別對映提供了更多的與存取能力,你知道它們嗎?,剩下的問題就是如何使用它們:
class A { /*...*/ }; class B : virtual A { /*...*/ }; struct C : A { /*...*/ }; struct D : B, C { /*...*/ }; A a1; B b1; C c1; D d1; const A a2; const A& ra1 = a1; const A& ra2 = a2; char c;
1.以下新的型別對映沒有同等的C的型別對映嗎?
const_cast
dynamic_cast
reinterpret_cast
static_cast
2.以下的每一個C的型別對映中,用同等的新的型別對映來寫,如果不用新的型別對映來寫,它們是錯的嗎?
void f() { A* pa; B* pb; C* pc; pa = (A*)&ra1; pa = (A*)&a2; pb = (B*)&c1; pc = (C*)&d1; }
3.評價以下C++型別對映後的型別與正確性。
void g() { unsigned char* puc = static_cast 解決方法: 比舊的C的型別對映,在標準C++中新的型別對映提供了更多的安全與存取能力,你知道它們嗎?,剩下的問題就是如何使用它們: class A { /*...*/ }; class B : virtual A { /*...*/ }; struct C : A { /*...*/ }; struct D : B, C { /*...*/ }; A a1; B b1; C c1; D d1; const A a2; const A& ra1 = a1; const A& ra2 = a2; char c; 1.以下新的型別對映有同等的C的型別對映嗎? 只有dynamic_cast沒用同等的C的型別對映,所有其它的新的型別對映都有相應的舊的型別對映。 2.以下的每一個C的型別對映中,用同等的新的型別對映來寫,如果不用新的型別對映來寫,它們是錯的嗎? void f() { A* pa; B* pb; C* pc; pa = (A*)&ra1; 使用 const_cast: pa = const_cast(&ra1); pa = (A*)&a2; 這是錯誤的,沒有同等新的型別對映,const_cast是替代者,但因為a2是const,結果不明確。 pb = (B*)&c1; 使用 reinterpret_cast: pb = reinterpret_cast(&c1); pc = (C*)&d1; } 上面的型別對映在C是錯誤的,在C++裡,沒有對映需要:pc = &d1; 3.評價以下C++型別對映後的型別與正確性。 開始,先宣告:我們不知道這些類任何一個是否有虛,如果這類不包含虛擬函式的話,以下所有dynamic_case全是錯的,剩下的討論部分,我們假定所有類都有虛擬函式,讓使用dynamic_cast是合法的, void g() { unsigned char* puc = static_cast 錯誤:對以上兩行我們必須使用reinterpret_cast,這個首先讓你感到驚奇的,但理由是char,singed char與unsigned char是三個不同的型別,在它們之中任何透過對它們進行明確的轉換都是沒有相聯的,所以指向無關的的物件, void* pv = static_cast 兩者之間是有細微的地方,但前者不是必須的,因為它總是明確地從物件指標向void*指標進行轉換。 B* pb2 = static_cast(&b1);
這兒有細微的地方,但不必要的,因為引數已經是B*. This is fine, but unnecessary since the argument is already a B*. A* pa1 = const_cast(&ra1);
這是合法的,但對映成const是通常缺少型別才進行的,大部分的情況下,在哪兒移去指標的const或引用相關到型別成員與關鍵字的掩蓋是合法的,在有更多的關於const的正確用法 A* pa2 = const_cast(&ra2);
錯誤:如果指標在物件裡使用寫將產生不確定的行為,原因a2實際上上是const物件,為什麼呢?,思考是允許a2建立同樣的const物件與使用它的資訊在只讀中並作最佳化, 註釋:我沒有給出使用const_cast轉換成非const指向const指標的示例,理由是這是多餘的,它早已是合法的分配非const指標指向const指標,我們只需要const_cast 去做相反的事。 B* pb3 = dynamic_cast(&c1);
錯誤(如果你嘗試使用pb3):因為c1不是A B(原因:C不是起源於B,在實際上它也不完全起源於B),它將pb3設為NULL,唯一正確的型別對映是使用reinterpret_cast,而且使用它始終是不幸的。 A* pa3 = dynamic_cast(&b1);
錯誤:因為b1不是A A(原因:B不是起源於A,但它起源是虛基類A(也就是說從虛基類派生的都不能轉換成該基類的型別)),這是的。 B* pb4 = static_cast(&d1);
這兒有細微的地方,因為源於基類的指標轉換是不需要明確宣告所以不需要。 D* pd = static_cast 這兒有細微的地方,如果你預期這兒需要dynamic_cast的話是你會吃驚的。理由是當目標是已知道的時候,向下對映是靜態的,但要小心:你是說編譯器在事實上知道你的,它為什麼開始指向實際上的它的型別,如果你錯了,那麼型別對映就不能通知你有問題(像dynamic_cast一樣,如果型別對映失敗它將返回空指標),且最多你能取得非真實的執行時錯誤與崩潰。 pa1 = dynamic_cast(pb2); pa1 = dynamic_cast(pb4);
這兒有兩個看起來很相似,它們都嘗試使用dynamic_cast把B*轉換成A*,然而,第一個是錯誤的而第二個是對的。 這兒有個理由:同上面的註釋,你不能使用dynamic_cast去對映指向實際上是B物件(pb2是指向b1物件)成A物件,因為B是從A進行私有繼承,非公有繼承,然而,第二個對映成功是因為pb4指向物件d1,且d像A一樣是間接派生於基類(透過C),與dynamic_cast是允許對映越過繼承體系,使用這種路徑B* -> D* -> C* -> A*. C* pc1 = dynamic_cast 這兒有兩個很細微,與前面的理由一樣:dynamic_cast透過繼承體系進行對映,所以這是合法且成功。 C& rc1 = dynamic_cast 最後,這而也有細微的地方...,因為*pb2不是實際上上的a C,dynamic_cast將執出bad_cast異常失敗訊號。為什麼呢?如果對映失敗,dynamic_cast將返null,但這兒引用的物件是空的,如果引用失敗那它不能返回空的引用,這兒除了丟擲異常外沒有失敗的訊號傳送到客戶端,所以那兒為什麼只有bad_cast異常。 一些個人看法: 1.to:%22cber@.com.cn%22">cber
2.:One for compile time, one for runtime. I think.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-974409/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Guru of the week:#19 自動型別轉換. (轉)型別
- C++ articles:Guru of the Week #1 (轉)C++
- Guru of the week:#18 迭代指標. (轉)指標
- Guru of the Week 條款19:自動轉換 (轉)
- Guru of the Week 條款27:轉呼叫函式 (轉)函式
- TypeScript 對映型別TypeScript型別
- C++ articles:Guru of the Week #4 -- Class Mechantics (轉)C++
- Guru of the Week 條款28:“Fast Pimpl”技術 (轉)AST
- Guru of The week #20 程式碼的複雜性 Ⅰ. (轉)
- TypeScript 之對映型別TypeScript型別
- C++ articles:Guru of the Week #3:使用標準庫 (轉)C++
- Guru of the Week 條款09:記憶體管理(上篇) (轉)記憶體
- Guru of the Week 條款10:記憶體管理(下篇) (轉)記憶體
- Guru of the Week 條款24:編譯級防火牆 (轉)編譯防火牆
- Guru of the Week 條款30附錄:介面原則 (轉)
- Generic:型別和值之間的對映 (轉)型別
- Guru of the Week 條款05:覆寫虛擬函式 (轉)函式
- Guru of the Week 條款13:物件導向程式設計 (轉)物件程式設計
- Guru of the Week #5:虛擬函式的重新定義 (轉)函式
- Guru of the Week 條款07:編譯期的依賴性 (轉)編譯
- Guru of the Week 條款11:物件等同(Object Identity)問題 (轉)物件ObjectIDE
- Guru of the Week 條款14:類之間的關係(上篇) (轉)
- Guru of the Week 條款15:類之間的關係(下篇) (轉)
- 17-Swift型別轉換Swift型別
- EF:自定義Oracle的對映型別Oracle型別
- SqlServer與.NET的資料型別對映關係圖(轉)SQLServer資料型別
- 如何使用Java泛型對映不同的值型別Java泛型型別
- elasticsearch的object型別和動態對映ElasticsearchObject型別
- EF:oracle的number型別對映為C#的boolean型別Oracle型別C#Boolean
- TypeScript 官方手冊翻譯計劃【十】:型別操控-對映型別TypeScript型別
- 搞懂 TypeScript 中的對映型別(Mapped Types)TypeScript型別APP
- Redis - 資料型別對映底層結構Redis資料型別
- Sybase datetime型別對映為Oracle timestamp型別Oracle
- Hibernate 對映xml中的屬性型別XML型別
- Guru of the Week 條款16:具有最大可複用性的通用Containers (轉)AI
- [Hibernate求助]如何構造自己的對映型別?型別
- HIBERNATE的自定義型別主鍵的對映??型別
- Guru of the Week 條款08:GotW挑戰篇——異常處理的安全性 (轉)Go