2010-06-24 32 views
-1
class A { 
public: 
    A() { } 
    ~A() { cout << "A Destructor \n" ; } 
}; 

class B :public A{ 
    public: 
    B() { } 
    virtual ~B() { cout << "B Destructor \n" ; } 
}; 

class C : public B { 
    public: 
    C() { } 
    ~C() { cout << "C Destructor \n"; } 
}; 

int main() 
{ 

    A *pointA = new A; 
    A *pointB = new B; 
    A *pointC = new C; 

    delete pointA; 
    delete pointB; 
    delete pointC; 
} 
+4

這是功課嗎? – Patrick 2010-06-24 10:36:44

+0

必須與帕特里克一致,聞起來像功課。 – Puppy 2010-06-24 10:45:35

+0

這不是作業。我試圖理解,爲什麼會拋出未定義的行爲? – user373215 2010-06-24 10:49:10

回答

10

它會在第二次(和第三次)刪除時調用未定義的行爲,因爲A的析構函數不是虛擬的。

§5.3.5/ 3:

如果靜態類型的操作數是從它的動態類型不同,則 靜態類型應爲基類操作數的動態型的和靜態型應有一個虛擬析構函數或行爲未定義。


如果你犯了一個虛擬的析構函數,你得到良好定義的行爲,並動態類型的析構函數被調用。 (以及每個那些反過來的調用基析構函數)。您的輸出將是:

析構函數
乙析
析構函數
Ç析
乙析
析構函數


什麼是值得的,當你接近一個可編譯的片段時,你應該離開t他包括。此外,只需使用struct而不是class來簡化public的內容,並省略空的構造函數。

+0

非常感謝Gman。 – user373215 2010-06-24 12:15:23

0

正如GMan指出的,試圖在基指針上調用delete操作符需要虛擬析構函數來讓編譯器能夠正確銷燬子類對象。很多人把這個過分簡化爲一條規則,比如「如果一個類有虛函數,它需要一個虛擬析構函數。」情況並非一定如此;即使沒有虛函數的基類仍然需要虛析構函數,如果你想允許客戶端通過基指針來刪除類。如果你不這樣做,析構函數應該受到保護,而不是公開的。

有一本很好的書,詳細描述了這一點,更多的稱爲Herb Sutter的C++編碼標準。我推薦它作爲C++冒險的起點。 :-)