作為通常的原則,如果一個類定義了虛函數(shù),那么它的析構(gòu)函數(shù)就應當是virtual的。因為定義了虛函數(shù)則隱含著:這個類會被繼承,并且會通過基類的指針指向子類對象,從而得到多態(tài)性。
這個類可能會被繼承,并且會通過基類的指針指向子類對象”,因此基類的析構(gòu)函數(shù)是否為虛將決定子類的對象是否被析構(gòu)。
很多時候你只能夠獲取基類指針,但卻不知道它實際是哪個子類,這時候刪除基類指針時虛析構(gòu)函數(shù)就很有用了。
#include <iostream>
using namespace std;
struct A
{
A(){cout << "A::()"<<endl;}
virtual ~A() {cout<<"~A()\n";}
};
struct B: public A
{
B(){cout << "B::()"<<endl;}
~B() {cout<<"~B()\n";}
};
int main()
{
A* p = new B;
delete p;
//B b;
return 0;
}
如果 A的析構(gòu)函數(shù)不是virtual的,那么此時就不是先調(diào)用B的析構(gòu)函數(shù)再調(diào)用A的析構(gòu)函數(shù)。
輸出:
~A();
如果A
的析構(gòu)函數(shù)為virtual,則先~B(),再~A()
輸出:
~B();
~A();
類如果會被派生的話,析構(gòu)函數(shù)一般都應該定義為virtual的,主要不是防止內(nèi)存泄露,而是為了正確的析構(gòu)。如果是個封閉類(即不再被派生),就不要定義為virtual的。虛函數(shù)畢竟耗費較大的。
不用virtual 的幾種情況:
1、作為非公有基類。僅作為 private base class 使用的 class
不需要使用虛擬析構(gòu)函數(shù)
2、不作為接口使用的基類。
3.
如果你可以保證這個類不被public繼承(private/protected繼承的話,在非friend函數(shù)/類中就無法用基類指針指向派生類了)
4. 如果它的所有派生類(包括派生類的派生類)的析構(gòu)函數(shù)都是trivial的(這里的trivial指的是在程序員的層次什么事也不做)
5. 如果不需要用基類的指針指向派生類的對象
在這五種情況下,不把析構(gòu)函數(shù)聲明為virtual都是可以的,何況效率會高一些——但前提是你得保證前提的成立——不過這些保證常常是很難100%的:誰能保證別人在派生你的類的時候,析構(gòu)函數(shù)是trivial的,或者別人不用你提供的基類的指針指向派生類對象?這些常常是很難得到保證的。
聲明基類的析構(gòu)函數(shù)為virtual并非總是為了防止memory leak
另外這也只是作為一般的原則(基類中有虛函數(shù)則把其析構(gòu)函數(shù)聲明為virtual)。如果你的析構(gòu)函數(shù)什么事也不作,從效果上來說,不聲明為virtual也無妨