2010-06-15 44 views
10

在這一點上,我對C++的瞭解比其他任何東西都更具學術性。在我所有的閱讀迄今爲止,使用一個名爲強制類型轉換(const_caststatic_castreinterpret_castdynamic_cast)顯式轉換來了一個大警告標籤(這很容易明白爲什麼),這意味着顯式轉換是對症糟糕的設計和只能在絕望的情況下作爲最後的手段使用。所以,我要問:C++顯式轉換真的很糟嗎?

與名爲顯式轉換蒙上真的只是陪審團舞弊代碼或者是有一個更優雅,積極應用到這個功能嗎?後者有一個很好的例子嗎?

回答

19

有些情況下,你不能沒有它。像this one。這個問題有,你有多重繼承,需要this指針轉換void*同時確保該進入void*指針仍將指向當前對象的右側子對象。使用明確的轉換是實現這一目標的唯一方法。

有一種觀點認爲,如果你不能沒有演員,你的設計就不好。我完全同意這一點 - 不同的情況是可能的,包括上面提到的一種情況,但也許如果你需要經常使用明確的演員陣容,那麼你確實有不好的設計。

+9

我同意sharptooth在這裏的最終評論,僅僅因爲你有一個明確的轉換並不意味着你有錯誤的代碼,但是如果你每隔一行轉回去轉發,那麼你需要重新思考。鑄造是一種有效的操作,但它不應該被過度使用。 – 2010-06-15 13:45:50

+1

當然從來沒有用過擺脫編譯警告和錯誤! – Alan 2010-06-15 16:26:31

11

有些情況下,您無法避免顯式強制轉換。尤其是在與C庫或設計錯誤的C++庫(如COM庫作爲示例使用的銳利庫)交互時。

一般來說,使用顯式演員是一個紅色的鯡魚。它並不一定意味着不好的代碼,但它確實吸引人們注意潛在的危險用途。

但是,您不應該將4個演員放在同一個包中:static_castdynamic_cast經常用於上演(從基礎派生到派生)或在相關類型之間進行導航。它們在代碼中的出現是非常正常的(實際上,如果沒有其中的任何一個,就很難編寫Visitor模式)。

在另一方面,利用const_castreinterpret_cast是更危險的。

  • 使用const_cast嘗試修改只讀對象是不確定的行爲(感謝詹姆斯McNellis修正)
  • reinterpret_cast通常只用來處理原始內存(分配器)

當然,它們有它們的用途,但不應在正常代碼中遇到。對於處理外部或C API,它們可能是必要的。

至少這是我的意見。

+1

從技術上講,它只是通過'const_cast'的結果修改一個只讀對象,導致未定義的行爲。 'const_cast'本身是「安全的」。 – 2010-06-15 14:18:59

+0

謝謝,我相應地調整了句子。有效地,任何強制轉換本身都是安全的,它只使用可能引發未定義行爲的結果。 – 2010-06-15 14:35:06

+0

COM不是C++庫,因此沒有考慮到良好的C++語義。這並沒有讓它變得糟糕 - 它只是定義了它自己的對象模型。 (COM是*其他*理由PITA) – 2010-06-15 15:22:00

3

海事組織,像大多數事情一樣,它們是工具,具有適當的用途和不適當的用途。鑄造可能是其中的工具經常得到使用不當,例如,具有reinterpret_cast(可在平臺上,其中兩個是不同的尺寸打破),或const_cast遠常量性純粹作爲一個黑客的int和指針類型之間施放的區域, 等等。

如果你知道他們是什麼和預期用途,但絕對沒有錯,他們使用什麼他們設計的。

6

演員陣容多麼糟糕通常取決於陣容的類型。所有這些演員陣容都有合法的用途,但有些人的氣味比其他人差。

const_cast用於鑄造const(因爲添加它不需要轉換)。理想情況下,永遠不要使用。它可以很容易地調用未定義的行爲(嘗試更改最初指定爲const的對象),並且在任何情況下都會中斷const-程序的正確性。有時需要與本身不是const的API進行接口時,它可能會要求char *將它當作const char *,但由於您不應該以這種方式編寫API,所以它是您的標誌'正在使用一個非常舊的API或者有人搞砸了。

reinterpret_cast總是要取決於平臺,因此在可移植代碼中最好是有問題的。而且,除非您對物體的物理結構進行低級別操作,否則不會保留意義。在C和C++中,類型應該是有意義的。一個int是一個數字,意味着什麼;一個int這基本上是連接的char s並不意味着什麼。

dynamic_cast通常用於向下轉換;例如從Base *Derived *,條件是要麼它工作,要麼返回0.這顛覆OO的方式與類型標記中的switch語句非常相似:它移動定義類與類定義不同的代碼。這將類定義與其他代碼結合起來並增加了潛在的維護負載。

static_cast用於已知通常是正確的數據轉換,例如從void *轉換到類別層次結構中已知的安全指針類型轉換等等。關於最糟糕的是你可以說它在某種程度上顛覆了類型系統。當與C庫或標準庫的C部分接口時,可能需要使用它,因爲經常在C函數中使用void *。一般來說,設計良好且編寫良好的C++代碼將避免上述用例,在某些情況下,因爲只有使用cast會做潛在的危險事情,而在其他情況下,因爲這樣的代碼往往會避免這種轉換的需要。 C++類型的系統通常被認爲是一件好事,並且會將其顛覆。

1

明確的演員有一個諷刺。開發人員的C++設計技能很差,導致他編寫需要大量投射的代碼的是同一開發人員,他們沒有適當地使用顯式投射機制,或者根本不使用顯式投射機制,並將其代碼與C風格演員混爲一談。另一方面,理解他們的目的,什麼時候使用它們,何時不使用,以及替代方案的開發人員不會編寫需要大量投射的代碼!


檢查出這些類型轉換的更細粒度的變化,如polymorphic_cast,在升壓轉換庫,給你的程序員是多麼小心C++是當它涉及到鑄造的想法。

1

鑄件是一種標誌,表示您正試圖在方孔中放置一個圓釘。有時候這是工作的一部分。但是如果你對孔洞和釘子都有一定的控制力,最好不要創造這種條件,寫劇本應該引發你問自己是否有某件事情可以做,這樣會更平滑。