2010-10-25 39 views
2

我檢討C++蒙上運營商,我有以下疑問:的static_cast時,基地不變成多態多形性

多態類

  • II應該使用polymorphic_cast
  • 我應該從不使用static_cast,因爲向下投射可能會導致未定義的行爲。代碼無論如何編譯這個案例。

現在假設我有以下situtation

class CBase{}; 
class CDerived : public CBase{}; 

int main(int argc, char** argv){ 
    CBase* p = new CDerived(); 
    //.. do something 
    CDerived*pd = static_cast<CDerived*>(p); 
} 

由於沒有多態性參與我不會用polymorphic_cast和代碼甚至不會編譯。

如果在某些時候,某人在繼承樹中引入了一些virtual函數,我現在意識到了這一點,所以我處於危險之中:我怎麼能意識到這一點?

我應該搬到polymorphic_cast以避免任何風險,但代碼仍然會在沒有任何通知的情況下編譯。

你怎麼做才能認識到這種變化或防止這些情況?

由於 AFG

+0

*並且代碼甚至不會編譯* - 你的意思是*並且代碼會編譯好*? – 2010-10-25 08:38:59

+1

不應該爲CBase「析構」虛擬嗎?在這種情況下,你可以使用'dynamic_cast'或'polymorphic_cast'。 – Naveen 2010-10-25 08:40:30

+2

在標準C++中沒有'polymorphic_cast'這樣的東西。爲什麼不首先使用'CDerived'?或者如果你認爲你必須使用動態分配,爲什麼不使用'CDerived *'?虛擬功能即使在不知情的情況下也不會造成任何危險。那些類名稱上的所有這些「C」前綴是什麼?這聽起來像是一個嚴重的口吃我的情況。乾杯, – 2010-10-25 08:46:22

回答

3

背景,你不包括 - 升壓具有polymorphic_cast圍繞dynamic_cast<>的包裝時,轉換失敗拋出。 static_cast<>很好,如果你確定數據的類型是你正在投入的......沒有或沒有虛擬成員沒有問題,你所包含的代碼說它不會編譯將編譯和運行就好原樣。

我想你正在考慮可能會意外投到另一個派生類?這是鑄造的效用/危險,不是嗎?您可以添加一個虛擬析構函數,然後使用dynamic_cast <>,嚴格地說,RTTI僅適用於具有一個或多個虛擬函數的類型。

用static_cast編寫的代碼<>將繼續安全地處理同一類型,而不管引入虛函數是什麼......只是如果您開始將該代碼傳遞給其他類型(即不是CDerived或由此公開派生的任何其他類型),那麼您將需要dynamic_cast <>或其他一些更改以防止不兼容的操作。

+0

Hi Tony!我喜歡這個想法。虛擬到析構函數默認情況下會阻止我的問題,同時我也不會泄露任何東西。非常感謝! – 2010-10-25 09:49:29

+0

@ abruzzo-forte-e-gentile:我知道很多人選擇這樣做(默認情況下爲虛擬析構函數) ,但要注意這裏有一些代價,它很小,但我認爲你應該只使用析構函數虛擬,如果你期望類使用多態(即在至少另一種方法也被宣佈爲病毒)。 – beldaz 2010-10-28 03:00:22

0

polymorphic_cast不C++定義。你在考慮dynamic_cast嗎?

無論如何,你無法做任何事情來阻止它。

+0

'boost'具有'polymorphic_cast',我猜OP正在使用它。 – Naveen 2010-10-25 08:44:35

1

當你處理指針p(類型CBase *)時,被指向的對象將被視爲一個CBase,但是所有的虛函數都會做正確的事情。指針pd將相同的對象視爲CDerived。以這種方式上傳很危險,因爲如果對象不是來自上傳類型,那麼上傳對象的任何額外成員數據都將丟失(這意味着您將在其他數據中查找),並且虛函數查找將會都搞砸了。這與向下轉換相反(正如您標記此問題),您可能會得到slicing

爲了避免這種情況,你需要改變你的編程風格。把兩個不同類型的對象作爲一個可疑的練習。 C++在執行類型安全方面非常出色,但如果你真的想要,或者只是不知道更好,它可以讓你擺脫討厭的東西。如果你想根據對象類型做不同的事情,並且不能通過虛擬功能(例如通過double dispatch)來完成,你應該更深入地瞭解RTTI(look here,或者查看一些很好的例子here)。