C++---之帶有virtual的解構函式概念
C++解構函式加上virtual是為了防止記憶體洩漏。
用在C++實現多型的時候,其基類要加virtual。
原因跟動態繫結有關,大家都知道,多型是通過虛擬函式實現的,而虛擬函式又是通過動態繫結實現的。
先舉個例子:
-
class Base
-
{
-
public:
-
virtual void function()
-
{
-
cout<<"this is Base's function"<<endl;
-
}
-
virtual ~Base()
-
{
-
cout<<"this is Base's destroy"<<endl;
-
}
-
};
-
class Derived:public Base
-
{
-
public:
-
void function()
-
{
-
cout<<"this is Derived's function"<<endl;
-
}
-
~Derived()
-
{
-
cout<<"this is Derived's destroy"<<endl;
-
}
-
};
-
int main()
-
{
-
Base *ptr = new Derived();
-
ptr->function();
-
delete ptr;
-
return 0;
-
}
上面的程式碼,我先寫了虛擬函式function,第31行就是動態繫結,而33行delete刪除的是Base型基類指標,此指標是沒有派生類Derived的解構函式的,所以如果不在基類的解構函式加上virtual的話,就不能動態繫結派生類的解構函式(當然解構函式的動態繫結你可以看出來跟一般函式的動態繫結相比是特殊的,解構函式的虛擬函式不用按照函式名來找對應的的函式)。一句話:基類的解構函式加了virtual就可以動態繫結派生類的解構函式,這樣的話,在執行多型後刪除其物件,就可以在刪除物件的時候執行派生類的析構函數了(當然執行基類的解構函式是一定會的)。否則不會執行派生類的解構函式。
程式碼輸出結果:
this is Derived's function
this is Derived's destroy
this is Base's destroy
你可以嘗試一下把基類的解構函式前的virtual刪掉(第9行),輸出結果將是:
this is Derived's function
this is Base's destroy
一、建構函式
1.建構函式任何時候都不可以宣告為虛擬函式,原因如下:1)虛擬函式的呼叫軍需通過虛擬函式表vtable來呼叫,虛擬函式表是儲存在記憶體空間的,在呼叫建構函式前,物件還未被實力化,也就沒有該物件的記憶體空間,也無法找到虛擬函式表;2)虛擬函式表實在物件構造之後才建立的,所以建構函式不可能是函式。
2.不能在建構函式內呼叫虛擬函式,原因如下:假設有個class繼承體系,如下程式碼,在該base class 的建構函式中呼叫虛擬函式,
class A{
public:
A();
virtual void print() const = 0;
.......
};
A::A(){
.......
print();
}
class B : public A{
public:
B();
virtual void print() const;
......
};
int main(){
B b;
}
當構造B的物件時,B的base class 成分肯定會在derived class 構造之前先構造,神奇的是此時A的建構函式呼叫的print()為A類內版本,因為base class構造期間,virtual函式絕不會下降到derived class階層,因為base class構造期間,derived class成員變數尚未初始化。
二、解構函式
1.類的設計目的如果不是作為base class使用,或不是為了具備多型性,解構函式就不該宣告為虛擬函式,原因如下:因為有虛擬函式的類就會有虛擬函式表存在,故物件體積會變大,同樣因為虛表指標的存在,使得C++中類的物件不在和其他語言(如C)內的相同宣告有著一樣的結構,,因此也就不再可能把它傳遞至或接受其它語言所寫的函式,故不在有移植性(除非你名確補償vptr)。
帶多型性質的base class或類中帶有任何virtual函式,就一定要擁有一個virtual解構函式,原因如下:假設derived class物件經由base class指標被刪除,而該base class帶著一個non-virtual解構函式,實際執行時通常會發生物件的derived成分沒有被銷燬。
2.不能在解構函式內呼叫虛擬函式,原因如下:一旦derived class解構函式開始執行,物件的derived class成員就會呈現未定義值,所以C++ 就會視它彷彿不存在,進入base class析構後,物件就成為一個base class物件,而virtual函式和 dynamic_casts也這麼認為,這也就失去了它動態呼叫的意義了。
--------------------- 作者:Su_720 來源:CSDN 原文:https://blog.csdn.net/luoxue720/article/details/75093855?utm_source=copy 版權宣告:本文為博主原創文章,轉載請附上博文連結!