2012-05-01 37 views
4

可能重複:
Regular cast vs. static_cast vs. dynamic_cast
Undefined, unspecified and implementation-defined behaviorC++類型轉換INT *上課

我面臨的一個奇怪的問題。在下面的代碼片段,我定義一個類

​​

在我的main()方法,我寫:

 void main() 
     { 
      int *ptr = new int(); 
      NewClass *n = ((NewClass *)ptr); 
      n->Test(); 
     } 

,並顯示 「的NewClass測試」。我不明白如何將任何指針鍵入NewClass並仍然有效。

在此先感謝!

+9

未定義的行爲意味着*任何事情*都可能發生,包括愚弄你認爲它有效。 –

回答

3

這是工作中的靜態調度。在這種情況下,this確實是不必要的(例如,它在NewClass::Test()內不被使用或依賴)。

鑄造爲NewClass *n = ((NewClass *)ptr);是按地址類型轉換,並且在此上下文中沒有類型檢查。換句話說,您並不是在任何地方創建新的實例,只是簡單地將int*指定的地址視爲NewClass*。這是一個應該避免的危險轉換。如果您需要通過丟失類型安全的地址(例如void*)漏斗,請始終確保兩端都知道發送和接收的內容。幸運的是,擦除型安全正在變得不太常見。

結果是不確定的,但在大多數情況下您應該預期會有不良副作用,您應該避免不惜一切代價重新解釋數據。

在這種情況下,編譯器可能會插入結果,因爲它知道它們。此外,由於在這種情況下沒有實際依賴於對象的地址或狀態:Test()不依賴於this的狀態/數據/成員/動態方法/ vtable。

如果你是會員,如std::string s添加到NewClass和打印這些還有......你能想到事情遲早比他們現在:)

做在事件炸燬的危險是不顯着:這是一個非常危險的轉換 - int*支持的所有數據將被重新解釋爲NewClass*,並且相應地重新解釋其所有內部存儲器和結構(例如vtables和魔術cookie)。在程序段錯誤發生前不會花費很長時間,或者通過讀取超出分配的末尾(int*),或者將int視爲完全不相關的類型 - 在這種情況下,考慮一個類的存儲器佈局vtable或數據,例如將一些std::string添加到NewClass,以及讀取和寫入這些成員。

+0

謝謝。我想知道NewClass對象在我的代碼中實例化的地方。我明白了關於沒有類型檢查的一點,也明白它是一種糟糕的編程習慣,無法將任何東西拋諸腦後。輸入讚賞。乾杯! – GeeKay

+0

@GeeKay這就是我所說的「按地址類型轉換」。沒有'NewClass' - 你只是簡單地將'int *'視爲'NewClass *':)你會發現'NewClass'在這種情況下不會被創建或銷燬。 (添加答案...) – justin

0

這看起來像未定義的行爲。但是,你總是可以在C++中使用reinterpret-cast來做到這一點。濫用reinterpret_cast操作符可能很不安全。除非所需的轉換本質上是低級別的,否則您應該使用其他演員操作員之一。 reinterpret_cast運算符可用於轉換,如char *到int *或One_class *到Unrelated_class *,這些本質上是不安全的。

0

您的方法未聲明爲虛擬。這意味着對它的調用完全由編譯器解決,就像它是一個非方法函數一樣,除了你必須調用一個你正在使用的形式爲NewClass的變量。

你的編譯器可能使用virtual method tables來調用虛擬方法,如果該方法是虛擬的,你最終可能會用垃圾代替VMT,然後你會開始崩潰。

也就是說,行爲是未定義的,意味着在任何情況下都可能發生任何事情。

1

在你開始考慮複雜的原因之前,不妨考慮一個簡單的場景來幫助你嘗試和描繪它。

一個類是附有方法的數據結構。當然,編譯器是不同的,所以行爲可以被認爲是未定義的,但暫時忽略它。

你有一個空的數據結構(即沒有數據),但仍然有一個方法 - 測試()。

所以當你聲明一個指向某個東西的指針時(int在你的注意下),指針只指向一些內存。現在你有一個新的Int(),因此ptr指向的內存是整數大小的。

由於你的類沒有數據,它沒有內部結構,它要求內存中的對象以特定的方式(例如虛擬方法)存儲在內存中,所以你可以認爲你指向任何東西或實際上什麼都沒有,因此可以調用你的方法。

像這樣創建一個類,並看看會發生什麼:

class NewClass 
    { 
     private int i; 
     public: 
     void Test() 
     { 
      cout<<"NewClass Test i="<< i << endl; 
     } 
    }; 

    void main() 
    { 
     int *ptr = new int(); 
     *ptr = 10; 
     NewClass *n = ((NewClass *)ptr); 
     n->Test(); 
    } 

看看它打印出來。

如果你明白這一點 - 請嘗試閱讀你的編譯器瞭解它如何佈局對象。這會告訴你很多關於你的平臺上存在這種行爲的原因。