2011-04-01 34 views
3

我在玩弄一些C++的未來,並進入了一些令我感興趣的東西。C++ inheritance

class Base 
{ 
     public: 
      Base(){ cout<<"C: Base"<<endl;} 
      ~Base(){ cout<<"D : Base"<<endl;} 
}; 
class Derived: public Base 
{ 
     public: 
      Derived(){ cout<<"C: Derived"<<endl;}   
      ~Derived(){ cout<<"D : Derived"<<endl;} 
}; 

class Derived2: public Derived 
{ 
     public: 
      Derived2(){ cout<<"C: Derived2"<<endl;} 
      ~Derived2(){ cout<<"D : Derived2"<<endl;} 
}; 

class Derived3: public Derived2 
{ 
     public: 
      Derived3(){ cout<<"C: Derived3"<<endl;} 
      ~Derived3(){ cout<<"D : Derived3"<<endl;} 
}; 

void main() 
{ 
     Derived *Var = new Derived2(); 
     delete (Derived3*)Var; //<---- this should cause some type of run-time error 
} 

爲什麼上面不會產生錯誤。是否因爲Derived3中沒有數據要發佈?或者我錯過了什麼?
而是將其輸出

C: Base 
C: Derived 
C: Derived2 
D : Derived3  <--- SHOULD NOT BE POSSIBLE 
D : Derived2 
D : Derived 
D : Base 

回答

6

C++語言沒有任何廣泛的「運行時錯誤」的系統。某些語言功能可能會拋出異常或調用terminate(),這確實是「運行時錯誤」,但無效delete不是這些功能之一。

做一些與你的東西無關的東西造成未定義的行爲在C++中。未定義的行爲意味着什麼都可能發生,任何事情都是可能的。你的程序甚至可能表現得好像它以某種方式「工作」。這是你觀察到的。

試驗未定義的行爲是沒有意義的練習。你觀察到的結果完全沒有意義,通常也不可重複。

+0

也許它不會被稱爲運行時錯誤,但如果你真的調皮的話,會終止你的位置...... – Jon 2011-04-01 00:34:51

+0

@Jon:你說得對。我更新了我的答案。謝謝。 – AnT 2011-04-01 00:40:29

0

它不會導致錯誤,因爲您的析構函數不會更改或觸摸任何本地狀態。

在典型的析構函數中,您將釋放該實例分配的某些資源,這會導致您期望的問題。

這就是說,它仍然不是很好的代碼,並且只發生,因爲你明確地轉換爲不正確的類型。在這種情況下,行爲在技術上是不確定的,這意味着會發生任何事情,包括現在正在進行的「工作」。

0

未定義的行爲可以做任何事情,包括出現工作。如果你做了非法的事情,編譯器或運行庫的工作就不是抱怨,只是爲了做正確的事情,如果你沒有做任何違法的事情。

2

您的演員陣容爲Derived3是一種C風格演員陣容,與以下C++風格演員陣容完全相同。

delete reinterpret_cast<Derived3*>(Var); 

這兩種類型轉換的告訴C++要強制運行時解釋由投(Var)作爲給定類型(Derived3*)並充分理解反響引用的內存運行。因此,不執行錯誤檢查。

如果您擔心中投的有效性,使用以下命令:

static_cast<Derived3*>(Var):生成一個編譯錯誤如果轉換是無效的。 dynamic_cast<Derived3*>(Var):如果強制轉換無效,則返回0(空)。

+1

從基指針到派生指針的C風格轉換實際上被視爲「static_cast」,而不是「reinterpret_cast」。在這個例子中,'static_cast'格式良好,不會*產生編譯錯誤,雖然大部分使用的結果指針都是Undefined Behavior。 – aschepler 2011-04-01 00:41:39