C 學習之虛析構函式

2022-07-09 20:15:11 字數 3439 閱讀 2144

類需要控制自己的物件執行一系列操作時發生什麼樣的行為,這些操作包括:建立(物件)、拷貝、移動、賦值和銷毀。在繼承體系中,如果乙個類(基類或其派生的類)沒有定義拷貝控制操作,則編譯器將自動的為其合成乙個。即為合成的拷貝控制。

基類拷貝控制中,由於繼承關係導致的最大影響就是:基類通常應該定義乙個『虛析構函式』。用以動態的分配繼承體系中的物件。

如:類a,b,c,d有如下繼承關係(**1):12

34classa;

classb:publica;

classc:publicb;

classd:publicc;

其中:類a定義如下(**2):12

345classa ;

當我們delete乙個a* item 

型別的指標時,該指標可能是指向a的,也可能指向的是b,c,d中的乙個,編譯器在delete時必須弄清楚到底應該執行a,b,c,d中哪乙個類的析構函式。此時需要編譯器進行動態繫結(即只有執行時才能知道到底item

指向的是那個類)。當在基類a中定義的析構函式為虛析構函式時,無論a的派生類(b,c,d)使用的是合成的析構函式還是自己定義的析構函式,它們都是虛析構函式。說人話就是:你老祖姓虛,傳到你還是姓虛,你兒子孫子都得姓虛(千萬別較真女生~~~),不管這兒孫是你血緣的還是你自己領養的,都得虛!

舉個例子(**3):12

34a *item =newa;//此時item指向的就是a,靜態型別於動態型別一致(這就是你本人)

deleteitem;//呼叫a自己的析構函式(自殺了,殺的是你自己)

item =newb;//靜態型別為a,動態型別為b(此時你的血脈傳到了你兒子身上,item是你兒子了!)

deleteitem;//呼叫b自己的析構函式(你兒子要自殺,此時死的是你兒子,和你無關)

如果基類a的析構函式不是虛的(虛函式),則delete時,如果item指向的不是a,而是b或其他a的派生類,則會產生未定義的行為,未定義的行為通常會導致bug。

那麼問題來了:什麼樣的情況下才需要虛析構函式呢?是所有類都應該有嗎?

通過基類的指標來刪除派生類的物件時,基類的析構函式應該是虛的。否則其刪除效果將無法實現。

簡單解釋一下,派生類b中所有的屬性以操作(bp)不僅有b自己定義的屬性、操作(bself),還有繼承自a的屬性、操作(aself),即bp=bself+aself;

如**3,當delete乙個指向b的item時(其實item的類型別為a),如果a中的析構函式不是虛的,則只會刪除aself部分,因為item的類型別其實是a,只是指向了其派生類物件。但是在a的析構函式裡其實並沒有bself部分,那這部分就刪不掉了--這就是所謂的記憶體洩漏!只有a的析構函式是虛的,才能刪除的不僅有aself,還有bself,即bp全部被刪除了。這才是正確的。

同時,並不是所有類都需要將析構函式定義成虛的。因為編譯器在編譯時會給類新增乙個虛函式表,裡面來存放虛函式指標,如果都定義成虛的,這樣就會增加類的儲存空間。浪費了!不用作基類,也不需要為虛的!不需要通過基類的指標來操作派生類的物件時,基類的析構函式應該是虛的。

這裡借用一下文章**:什麼時候要用虛析構函式? 12

3456

78910

1112

1314

1516

1718

classclxbase

;

virtual ~clxbase() {};

virtualvoiddosomething() ;

};

classclxderived :publicclxbase

;

~clxderived() ;

voiddosomething() ;

};

**

clxbase *ptest =newclxderived;

ptest->dosomething();

deleteptest;

正常情況應該輸出:12

do somethinginclassclxderived!

output from the destructor ofclassclxderived!

如果將類clxbase的析構函式定義為非虛(去掉前面的那個virtual),則輸出為:

1do somethinginclassclxderived!

根本沒有呼叫clxderived的析構函式哦~~~

同樣,在什麼時候要用虛析構函式? 中,提出了乙個這樣的問題:

為什麼繼承乙個沒有虛析構函式的類是危險的?

這個問題嗎其實上面已經解釋過了,會導致刪不完!記憶體洩漏問題。當你公有繼承建立乙個從基類繼承的相關類時,指向新類物件中的指

針和引用實際上都指向了起源的物件。因為析構函式不是虛函式,所以當你delete

乙個這樣的類時,c++就不會呼叫析構函式鏈。

來自為知筆記(wiz)

c 之虛析構函式

析構函式的作用是在物件撤銷之前做必要的 清理現場 的工作。當派生類的物件從記憶體中撤銷時一般先呼叫派生類的析構函式,然後再呼叫基類的析構函式。但是,如果用new運算子建立了臨時物件,若基類中有析構函式,並且定義了乙個指向該基類的指標變數。在程式用帶指標引數的delete運算子撤銷物件時,會發生乙個情...

C 之虛析構函式

相信大家都已經清楚了虛函式這個概念。在c 中,建構函式不能宣告為虛函式,而析構函式卻可以宣告為虛函式,大家可能對為什麼要把析構函式宣告為虛函式很疑惑,下面,雲主 博主 就帶大家去會會這個虛析構函式 首先,先看一段 incldue using namespace std class base 建構函式...

C 之虛析構函式

虛析構函式 如果乙個類有子類,則這個類 父類 的析構函式必須是虛函式 如果父類的析構函式不是虛函式,則當 delete 刪除乙個指向子類物件的父類指標 時,將呼叫父類版本的析構函式,子類只釋放了來自於父類的那部分成員變數,而子類自己擴充套件的成員變數沒有被釋放,造成記憶體洩漏 include std...