2012-10-17 42 views
5

爲什麼在下面的示例中調用所有析構函數~D()~C(),~B(), ~A()當派生類的析構函數是非虛擬的時,爲什麼基類析構函數在派生對象上調用?

只有一個虛擬析構函數:A

下面是代碼:

#include<iostream> 
using namespace std; 

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

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

int main() 
{ 
    A* ptr = new D(); 
    delete ptr; 
    return 0; 
} 
+1

因爲這是語言規則應該發生的事情。 – juanchopanza

回答

7

一旦A的析構函數聲明virtual,所有派生類的析構函數也virtual,即使他們沒有被明確宣佈爲..所以行爲你看到的是什麼,預計

+1

@spin_eight通過一個指向'A'的指針來訪問'D',這是調用刪除的內容。如果'A'的析構函數不是虛擬的,只會調用'〜A()'。你可以輕鬆地檢查自己。 – juanchopanza

+0

是的,謝謝! –

6

破壞秩序派生的對象進去完全相反的順序 建設:最衍生第一析構函數調用10個類,然後調用基類的析構函數。

析構函數可以定義爲虛擬甚至純虛擬。如果您希望通過指向基類的指針銷燬派生類 ,您將使用虛擬析構函數。這將確保 最派生類的析構函數將被調用:

A* b1 = new B;//if A has a virtual destructor 
delete b1;//invokes B's destructor and then A's 

A* b1 = new B;//if A has no virtual destructor 
    delete b1;//invokes A's destructor ONLY 

如果A沒有虛析構函數,通過A型的指針 刪除B1只會調用A的析構函數。要強制 B的析構函數的調用在這種情況下,我們必須指定的析構函數爲 虛擬:

virtual ~A(); 

REFERENCE

+0

「甚至純粹的虛擬」 - 何時爲了防止運行時錯誤,您必須爲純虛擬析構函數創建主體,以便在該析構函數的虛擬表中分配地址,而不僅僅是nullptr –

0

正如@juanchopanza說 - 宣佈基地析構虛指所有後代有虛擬析構函數。這種繼承的虛擬性是,對於任何方法都是相同的,而不僅僅是析構函數。

這就是爲什麼我採訪了那些不知道關鍵字是做什麼的人,因爲他們只能重寫從框架派生的方法,所以他們都是虛擬的(嘆氣)。

相關問題