2016-07-07 57 views
0
class A { 
.... 
}; 

class B: public A { 
int x; 
... 
}; 

class C: public A{ 
A * ptr; 
..... 
}; 

class D : public A { 
A* ptr1; 
A* ptr2; 
.... 
}; 

注:我提出的所有構造函數B,C,d只是不包括他們在那裏。 所以A(沒有字段)是超類,我有3個子類(B,C和D),每個都有不同的字段。(C++)子鏈破壞調用析構函數時

A是一個抽象類,它的大部分鏈接類(B,C,d)的

所以像我可能喜歡

B *x = new B {5}; 
B *x2 = new B {5} 
D * y = new D{x,x2); 

的情況所以,當我做delete y;我要打它連鎖破壞了它的兩個領域(B對象)的兩個指針。我如何讓D類的析構函數然後鏈式破壞?

就像我展示的例子非常簡單,但其他例子有越來越多的圖層。我想確保一切都被刪除,所以不會發生內存泄漏。

我的D類Dtor應該是這樣嗎?

~D(){ 
delete ptr1; 
delete ptr2; 
} 

對於C類的情況,我會這麼做嗎?

~C(){ 
    delete ptr; 
    } 

因爲我這樣做,它不工作我得到內存泄漏,所以最新錯了?

+3

你是否聲明你的析構函數是虛擬的? – Falmarri

+0

A級否。我認爲我可以重寫,如果我在子類中創建一個@Falmarri –

+0

它應該使類A析構函數是純虛擬的,並且我真的不需要爲B類做一個破壞,它可以使用它的默認權限? –

回答

0

我認爲你的問題是錯誤的,因爲你說這是繼承鏈,但是在寫BCD直接從A inhereting的時間。

當你做new D發生的事情是你必須由ABCD複合對象 - 他們是在繼承順序構成。

*y = { 
    // B starts 
    int x; 
    // C starts 
    A * ptr; 
    // D starts 
    A * ptr1; 
    A * ptr2; 
}; 

注意,析構函數會以相反的順序被調用,D第一則C等等,清理以相反的順序(處理依賴於超類)的內存。但是,這取決於您要刪除的對象類型。

如果我們這樣做:

D * y = new D; 
A * x = y; 
delete x; 

我們已經有效地處理yA對象,這意味着我們被限制在一個什麼物體A知道而只要能做到,因爲我們正在使用x。如果我們使用x刪除,我們將打電話~A()而不是~D()。這就是爲什麼在這種情況下,破壞者需要是虛擬的,這允許virtual ~A()呼叫~D(),這將最終再次呼叫~A()(真實的不是虛擬發貨)。

無論你是或不是使用多態/上溯造型,你的直覺是正確的 - ~D()只能清理內存D對象介紹到類(ptr1ptr2),同樣爲~C()(僅ptr) 。

泄漏將是因爲物體切片發生某處。例如(如果您強制編譯),這比上面的例子更糟糕,因爲對象數據將不會被複制(與結構定義相對於被引用對象的類型而言是不完整的)相反:

D d; 
C * c = d; // not too bad, we can't refer to D-specific things. 
C c2 = d; // bad, c2 is copied from D up to C superclass and no further. 

要非常小心,只傳遞指向可能需要保存派生類型的對象的指針/引用,以及確保使用虛擬析構函數的位置。否則你所做的是正確的,讓每個類的析構函數都爲那個類清理。