多型是由虛函式表來實現,通過父類指標來實現動態繫結。子類重寫父類的虛函式後,覆蓋虛函式表中父類該虛函式在表中原來的位置,也許「覆蓋」也就是由此得稱。
那析構函式是否也如此呢?程式**中經常可以見到將基類的析構函式寫成虛函式,目的就是為了防止由以下這種情況造成的記憶體洩漏:
class a;
class b : public a{};
......
b *b = new b();
a *p = (a*)b;
delete p;
此時系統僅呼叫了a的析構函式,並沒有呼叫b的析構函式,為什麼呢?指標p指向的是b的物件啊!
而且,為什麼將a的析構函式寫成虛函式,通過a類指標來delete就能呼叫析構b呢?難道又是動態繫結?可是,動態繫結的前提是兩個函式要有一致的宣告啊,這裡就算是~a();是virtual的,那也不能說會動態繫結到~b();去啊,起碼它們不是同名的。
開啟vc除錯後,在watch視窗檢視後得知,指標p和b的值一樣,可是把「+」展開後看到的卻不一樣,p展開後竟然沒有看到b的成員變數,由此猜測:這樣的話,那類b獨有的函式也同樣不能呼叫了(廢話,誰這麼用過)。那也就是說,通過指標p來delete,呼叫的當然也是a的析構函式了,難怪b的析構函式沒被呼叫。
a析構寫成虛函式後發現,b物件的虛函式表裡(展開指標p的「+」後)就出現了b的析構函式相關資訊,它覆蓋了原來a的虛析構函式,也只能覆蓋(怎麼覆蓋?這個......),否則通過基類指標不知要呼叫哪個函式(這麼猜不知對不對)。然後根據析構的順序,再呼叫a的析構函式。
還有乙個問題,為什麼指標b轉化為a類指標後,類b獨有的成員會不見呢,而且,虛函式表指標也是類b獨有的,為什麼它就還能留在那兒。這得從c++的物件記憶體模型說起brabra...,估計應該跟截斷技術有關,從派生層次上看(通過基類派生類的構造順序看),構造乙個派生類物件時,先構造父類的成員變數,然後......而c++為類物件結構的頭四個位元組初始化為虛函式表指標(從單繼承的角度),所以,截斷的時候仍然保留了(呵呵,是這樣吧)。
基類虛析構函式
why虛析構函式?主要還是由於基類指標或引用可以不進行顯示型別轉換的情況下指向派生類物件。同時通過引用或者指標或引用呼叫方法時遵循 例如 定義了基類brass,派生類brassplus 如果viewacct 不是虛方法,則b1 ref.viewacct 和b2 ref.viewacct 均是使用br...
多型基類與虛析構函式
假設我們有乙個基類a,很不幸的,a的析構函式是乙個non virtual。同時我們有乙個派生類b,它派生自a。我們定義了乙個a型別指標,它指向的實際物件是b a ptr new b 然後在程式的某處,我們不再需要b了,我們將指標ptr delete掉 delete ptr 注意new永遠要和dele...
確定基類有虛析構函式
有時,乙個類想跟蹤它有多少個物件存在。乙個簡單的方法是建立乙個靜態類成員來統計物件的個數。這個成員被初始化 為0,在建構函式裡加1,析構函式裡減1。條款m26裡說明了如何把這種方法封裝起來以便很容易地新增到任何類中,my article on counting objects 提供了對這個技術的另外...