#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;}
};
int main(void)
{
Base *p = new Derived();
delete p;
}
実行結果
Base::Constructor
Derived::Constructor
Base::Destructor
基底クラスのオブジェクトとして派生クラスのオブジェクトを生成し代入しているが、delete時に派生クラスのオブジェクトのデストラクタの呼び出しが行われないのである。仮に派生クラスのメンバ変数にポインタ等が含まれており、デストラクタでそのポインタのメモリを開放する記述を行っていた場合、デストラクタが呼び出されずにメモリリークの原因となってしまう。その為、継承の可能性のあるクラス(事実上ほぼ全て)のデストラクタは仮想デストラクタにしておく必要がある。そうすることによって、派生クラスのデストラクタが呼び出され、さらに基底クラスのデストラクタの呼び出しも正常に行われるのである。
#include<iostream>
using namespace std;
class Base{
public:
Base(){cout << "Base::Constructor" << endl;}
virtual ~Base(){cout << "Base::Destructor" << endl;}
};
class Derived:public Base{
public:
Derived(){cout << "Derived::Constructor" << endl;}
virtual ~Derived(){cout << "Derived::Destructor" << endl;}
};
int main(void)
{
Base *p = new Derived();
delete p;
}
実行結果
Base::Constructor
Derived::Constructor
Derived::Destructor
Base::Destructor
ちなみに「デストラクタは仮想デストラクタにしておく必要がある」とあるが、逆に継承を望んでいるクラスのデストラクタが仮想デストラクタで無い場合は、そのクラスが継承を想定していない(継承に対しての対策が無い)設計だという可能性も考える必要がある。