以下內容為本人的著作,如需要轉載,請宣告原文鏈接 微信公眾號「englyf」https://www.cnblogs.com/englyf/p/16631774.html
先說結論:
建構式不能宣告為虛函式,解構式可以宣告為虛函式,
建構式可以宣告為虛函式嗎?
虛函式表里都存了些什么東西?不是金,不是銀,是對應類里宣告為虛函式的成員地址,在編譯期,每個類的虛函式表即被分配和生成,同一個類的所有實體物件都是共享這個虛函式表的,那么每個實體物件也就會隱含有一個成員指標變數專門用來存盤虛函式表的地址,這個隱含的成員指標變數需要在實體物件初始化后才會指向虛函式表,
很顯然,物件不能在沒有初始化之前就知道自己對應的虛函式表在哪里,因此也不能在物件初始化之前呼叫訪問虛函式表的內容(虛函式),是不是在物件初始化之前就不能呼叫訪問這些虛函式成員了?不是這個意思,這里說的不能僅限于通過虛函式表來訪問(比如派生后的類實體物件通過父類的指標變數訪問呼叫虛函式成員),也就是動態訪問時才需要虛函式表的資訊,不過,就算某個成員函式被宣告為虛函式時,也可以通過類的靜態特性合法訪問的,這是無關痛癢的題外話,評價____,
物件的初始化就是依賴于建構式的執行,首先是找到最上一層父類的建構式并執行,然后逐層往下執行建構式,直到執行完當前類(被實體化的類)的建構式,這個程序不需要虛函式表的任何資訊,在編譯期就確定了所有需要的資訊了,在建構式執行之前,物件還無法確定自身的虛函式表在哪里,又怎么從虛函式表里查找對應的虛建構式呢?如果把建構式宣告為虛函式,那么意義在哪兒呢?想來想去,可能費勁打造出一把刀刃能削鐵如泥的好刀,卻只是在需要敲釘子時,想起用這把刀的刀背,
所以,很明顯建構式不能宣告為虛函式,
解構式可以宣告為虛函式嗎?
先看下面的代碼,解構式不宣告為虛函式時,
#include <iostream>
using namespace std;
class Base
{
public:
Base() {
cout << "Base constructor" << endl;
}
~Base() {
cout << "Base destructor" << endl;
}
};
class Derived : public Base
{
public:
Derived() {
cout << "Derived constructor" << endl;
}
~Derived() {
cout << "Derived destructor" << endl;
}
};
class Derived_again : public Derived
{
public:
Derived_again() {
cout << "Derived_again constructor" << endl;
}
~Derived_again() {
cout << "Derived_again destructor" << endl;
}
};
int main()
{
Base *obj = new Derived();
cout << "----" << endl;
delete obj;
return 0;
}
看看編譯后執行的結果(這里用的編譯器是g++)
Base constructor
Derived constructor
----
Base destructor
從上面的輸出來看,類Derived的解構式沒有被呼叫到,這會導致典型的問題--記憶體泄漏,
然后把所有解構式宣告為虛函式,重新編譯再看看執行結果
Base constructor
Derived constructor
----
Derived destructor
Base destructor
可以看到,需要呼叫的解構式都呼叫了,
那么怎么去理解上面這段代碼的執行邏輯呢?
delete obj;
銷毀物件時,系統執行的邏輯有兩種情況,
一種是,如果解構式沒有被宣告為虛函式時,那么在指標obj指向的物件的虛函式表里,是找不到虛解構式的,由于系統無法往下查找派生類的內容,而且變數obj被宣告為某個類(上面代碼對應的是Base)的指標型別,那么系統就轉為呼叫這個類(Base)的成員解構式,這里利用的是靜態特性,
另一種是,如果解構式被宣告為虛函式時,先在指標obj指向的物件的虛函式表里,嘗試尋找當前物件obj的虛解構式,找到后執行它,對應代碼,被實體化的類是Derived,物件obj的虛解構式地址應該指向類Derived的成員解構式,
上面兩種情況中,找到第一個解構式并執行后,會按照靜態特性(也就是按照編譯期生成的資訊),逐層往上一層父類查找成員解構式并執行,直到最上一層的父類的解構式被執行完畢為止,
于是,第一種情況下,類Derived的成員解構式被漏掉執行了,這會導致類Derived所申請的資源沒有對應的解構式來執行釋放,記憶體泄漏發生地那么順理成章,
可以看到,動態特性可以把事情玩得妥妥當當,面向物件的高級感可能就來自這里,
總結一下,很明顯,解構式可以宣告為虛函式,但不是必須,某些情況下,也是必須的,比如,當類指標指向的是該類的子類實體時,解構式必須宣告為虛函式,以防止記憶體泄漏,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/502914.html
標籤:其他
下一篇:作業系統的介紹
