ホームに戻る
出典 :
関連 :
目次 :
デストラクタの仮想化
継承 (Inheritance)でも述べたように、あるクラスが他のクラスを継承している場合、
- 生成時 : 基本クラスのコンストラクタ → 派生クラスのコンストラクタ
- 破棄時 : 派生クラスのデストラクタ → 基本クラスのデストラクタ
の順でコールされる。しかし、基本クラスのポインタが派生クラスを指す場合に問題が生じることがある。
#include <iostream>
using namespace std;
// 基本クラスの定義
class CBase {
public:
CBase () { cout << "CBase 生成" << "\n"; }
~CBase () { cout << "CBase 破棄" << "\n"; }
};
// 派生クラスの定義
class CDerived : public CBase {
public:
CDerived () { cout << "CDerived 生成" << "\n"; }
~CDerived () { cout << "CDerived 破棄" << "\n"; }
};
void main()
{
// #1 : 派生クラスのポインタが派生クラスのインスタンスを指す場合
CDerived* pcl_D = new CDerived();
delete pcl_D;
// #2 : 基本クラスのポインタが派生クラスのインスタンスを指す場合
CBase* pcl_B = new CDerived();
delete pcl_B ;
}
上記コードの実行結果
CBase 生成 //< #1 ここから
CDerived 生成
CDerived 破棄
CBase 破棄 //< #1 ここまで
CBase 生成 //< #2 ここから
CDerived 生成
CBase 破棄 //< #2 ここまで
#1 (派生クラスのポインタが派生クラスのインスタンスを指す場合)では正常にコールされているが、
#2 (基本クラスのポインタが派生クラスのインスタンスを指す場合)では派生クラスのデストラクタがコールされない。
これは pcl_B が「基本クラスのポインタ」であり、(指し示す先が派生クラスのインスタンスであっても)派生クラス固有のメンバにアクセスできないことが原因である。
この問題を回避するためには、 基本クラスのデストラクタを仮想化すればよい 。
// 基本クラスの定義 (修正)
class CBase {
public:
CBase () {}
virtual ~CBase () {} //< デストラクタを仮想化
};
// 派生クラスの定義
class CDerived : public CBase {
public:
CDerived () { cout << "CDerived 生成" << "\n"; }
~CDerived () { cout << "CDerived 破棄" << "\n"; }
};
デストラクタ仮想化の是非
実行時ポリモーフィズムを用いる場合(≒基本クラスがポリモーフィック(仮想関数を含む))は、デストラクタを仮想化する必要がある 。
これは基本クラスのデストラクタが有意な処理を行わない場合も同様である。(空の仮想デストラクタを定義する必要がある。そもそもデストラクタで何を行うかは問題ではない。)
しかし関数の仮想化は、
- (クラス情報が増えるため)インスタンスサイズが大きくなる
- 関数呼び出しが遅くなる
といった弊害があるため、以下のような場合は仮想化すべきではない。
- 実行時ポリモーフィズムを用いない
- そもそも継承を行わない