2010-04-10 123 views
13

我一直在讀的StackOverflow太多,開始懷疑所有我曾經寫過,我一直在想代碼「那是未定義水煤漿?」即使在代碼已經工作了很長時間。鑄造指針對象爲void *在C++

所以我的問題 - 它是安全和定義良好的行爲將一個指向對象(在這種情況下,抽象接口類)轉換爲void *,然後將它們轉換回原始類並調用使用它們的方法?

我充分認識到執行此代碼可能是可怕的。我甚至不會考慮現在這樣寫(這是舊的代碼,我不想改變),所以我不想討論更好的方法來做到這一點。如果我再次這樣做,我已經知道如何寫得更好。但是,如果實際上在C++中依賴於此,那麼我將不得不考慮更改代碼,如果它只是非常糟糕的代碼,那麼更改它就不是優先級。

我不會有任何有關的東西懷疑這個簡單的一兩年以前,但作爲我的C++的增加其實我覺得了解我對代碼越來越多的擔憂是在標準的安全,即使它工作得很好。也許讀太多堆棧溢出是因爲有時候生產力壞事:P

回答

16

你是安全的。

從C++(0X)草案,

§ 5.2.9/13(對於static_cast):

類型的指針的值,以對象轉換爲「指針CVvoid」和可能具有不同的簡歷資格,應具有其原始價值。

§ 5.2.10/7(用於reinterpret_cast):

轉換類型的右值「指針T1」的類型「指針T2」(其中T1T2是對象類型和其中的T2的對準要求並不比的T1嚴格)和返回到其原始類型產生的原始指針值。

(當然,鑄造到一個不相關的類是未定義的行爲。)

+1

雖然這種行爲在C++ 0x中當然沒有變化,但我認爲從不接受草案標準的草案引用來回答關於語言當前狀態的問題是不好的做法。 – 2010-04-10 14:27:13

+0

謝謝。在C++編程十年之後,我覺得這樣的基本問題很愚蠢,但我對C++的瞭解越多,我越是懷疑自己。其他人有這種感覺嗎? ...嗯,那就是我。 – jcoder 2010-04-11 10:40:44

8

所以我的問題 - 它是安全的和明確的水煤漿投一個指向對象(在這種情況下,抽象接口類)爲void *然後再將它們轉換回原始類並使用它們調用方法?

是 - 只要你施放回完全相同類型。否則,基類指針調整可能會破壞指針的值。

在實踐中,這一點使用多重繼承時是(可能)唯一相關:指針派生類可以在它們的物理地址不同的指針從它們的基類。

1

我們使用這種技術通常以避免在根據您所使用的環境中的每個單獨的類switch語句(基於Web,Windows和Linux等)

使用void **的引用。

void ** detailObject; 

創建函數返回引用的對象:

TheObject *TheClass::GetObject(){ 
    TheObject *object = (TheObject*)object; 
    return object; 
} 

只需使用函數作爲對象從現在開始。例如GetObject()->Go();