c++面向對象特性其中有多态這個特性,平時使用時用基類指針指向子類對象。當我們進行記憶體回收的時候調用 delete (基類指針),此實如果基類有一個non-virtual析構函數。這種情況下會導緻派生類的對象沒有被銷毀,隻有基類部分會被銷毀掉,于是造成一個詭異的“局部銷毀”對象。這樣的後果會形成資源洩露、資料結構被破壞、而且很難找出原因。
#ifndef _BASECLASS_H
#define _BASECLASS_H
class BaseClass
{
private:
/* data */
public:
BaseClass(/* args */);
~BaseClass();
};
#endif // _BASECLASS_H
#include "BaseClass.h"
#include <iostream>
BaseClass::BaseClass(/* args */)
{
std::cout << "BaseClass construct" << std::endl;
}
BaseClass::~BaseClass()
{
std::cout << "BaseClass destructor" << std::endl;
}
#ifndef _DERIVEDCLASS_H
#define _DERIVEDCLASS_H
#include "BaseClass.h"
class DerivedClass : public BaseClass
{
private:
/* data */
public:
DerivedClass(/* args */);
~DerivedClass();
};
#endif // _DERIVEDCLASS_H
#include "DerivedClass.h"
#include <iostream>
DerivedClass::DerivedClass(/* args */)
{
std::cout << "DerivedClass construct" << std::endl;
}
DerivedClass::~DerivedClass()
{
std::cout << "DerivedClass destructor" << std::endl;
}
BaseClass *base = new DerivedClass();
delete base;
輸出:
BaseClass construct
DerivedClass construct
BaseClass destructor
消除這個問題的做法很簡單:給base class一個virtual析構函數。此後删除derived class對象就會如你想要的那般,将整個對象都銷毀,包括derived class成分。
#ifndef _BASECLASS_H
#define _BASECLASS_H
class BaseClass
{
private:
/* data */
public:
BaseClass(/* args */);
virtual ~BaseClass(); // virtual修飾
};
#endif // _BASECLASS_H
運作程式,輸出:
BaseClass construct
DerivedClass construct
DerivedClass destructor
BaseClass destructor
如果class不含virtual函數,通常表示它并不意圖被用做一個base class。當class不企圖被當作base class,令其析構函數為virtual往往是個馊主意。因為使用virtual函數會導緻對象中有一個虛表指針(vptr),該表存在的目的就是為了實作多态的,但是會占用記憶體空間。這樣做的結果會導緻該對象不再和其他語言(如C)内的相同聲明有着一樣的結構(因為其它語言對應物并沒有vptr),是以也不再具有移植性。
請記住
- polymorphic(帶多态性質的)base class應該聲明一個virtual析構函數。如果class帶有任何virtual函數,它就應該擁有一個virtual析構函數。
- Classes的設計目的如果不是作為base classes使用,或不是為了具備多态性(polymorphically),就不該聲明virtual析構函數。