多态基类与虚析构函数
假設我們有一個基類A,很不幸的,A的析構函數是一個non-virtual。同時我們有一個派生類B,它派生自A。
我們定義了一個A類型指針,它指向的實際對象是B:
然后在程序的某處,我們不再需要B了,我們將指針ptr delete掉:
delete ptr;注意new永遠要和delete成隊出現,除非你使用智能指針。這時由于A的析構函數是non-virtual,一個悲劇誕生:
C++中明確指出,當派生類對象經由一個基類指針被刪除,而該基類帶著一個non-virtual析構函數,其結果未定義--實際執行時通常發生的是對象的派生部分沒有被銷毀。也就是B對象部分發生內存泄漏。
問題的解決辦法就是為多態基類A聲明一個虛析構函數。簡單吧,另一個更加通用的準則是:如果一個類擁有至少一個虛函數,那么這個類也應該要有一個虛析構函數,因為類中擁有虛函數已經表明該類將作為基類來使用,期待子類實現自己的虛函數,此時基類應該為析構函數作virtual聲明。
反過來的另一條準則是,如果一個類不想作為基類,那么不要為其聲明任何成員函數做virtual聲明。為啥?virtual有代價啊。為了支持多態機制,編譯器為類對象安插一個虛表指針,同時類也多了一張虛函數表。如果我們的類本來只有一個int類型的數據成員,在32bit機器上,sizeof(類)為4,而加了vptr后,sizeof(類)為8,類對象的大小整整翻了100%!
當然,就算我們的編程遵循了上面的準則,有時候還有有些許錯誤。切勿不要以沒有任何虛函數的類作為基類。有時候由于我們的粗心大意或者在毫不知情的情況下我們可能會干這種事情。例如,我們想實現一個自己的容器MyList,并想借助STL的list來實現:
class MyList :public list {//... };那么內存泄漏的問題又來了,STL中的list并不打算作為一個基類來使用,因此它的析構函數也不是一個virtual。類似的還有string、stl的vector、set、unordered_map等等。
好在,C++11 提供了final關鍵字,對于不想被繼承的類,我們在其定義時加上final關鍵字:
class Super final {//...... };這樣試圖繼承super時編譯器將會報錯。
轉載于:https://www.cnblogs.com/QG-whz/p/5126078.html
總結
以上是生活随笔為你收集整理的多态基类与虚析构函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#垃圾回收(GC)
- 下一篇: LightOJ1032 Fast Bit