virtualデストラクタ


概要

特定条件のデストラクタにはvirtualをつけなければならず、
virtualをつけ忘れるとデストラクタが呼び出されないことがあります。

virtualが必要な条件

virtualが必要なデストラクタの条件は仮想関数を持っている基底クラスがある場合です。

class Parent
{
public:
	Parent(){}
	virtual ~Parent() {}

	virtual void Print()
	{
		printf("Parentクラス\n");
	}
};

class Child : public Parent
{
public:
	Child() {}
	virtual ~Child() {}

	virtual void Print()
	{
		printf("Childクラス\n");
	}
};

上記のコードではParentクラスの「Print」関数は仮想関数となっているので、
基底クラスのデストラクタには「virtual」をつける必要があります。

virtualをつけなかった場合

cpp_0004
上記の内容で、問題のクラスの流れのmain関数では
ChildクラスをParentクラスにアップキャストしており、
そのアップキャストしたParentクラスの変数をdeleteしています。
この場合、派生クラスのデストラクタは呼び出されません。
呼び出されない理由はアップキャストの特性が原因です。

アップキャストの特性
派生クラスは基底クラスの情報を全て持っているので、
異なるデータ型であっても、キャストが成功する
アップキャストされた派生クラスは基底クラスのメンバしか使用できなくなる
上記の特性の②が主な原因です。 ParentでアップキャストされたChildクラスをdeleteで消去した場合、 Parentのデストラクタが呼び出されます。 本来、派生クラスのデストラクタは派生先から始まり、基底クラスのデストラクタに たどり着くのですが、今回は基底クラスのデストラクタが最初に呼ばれています。 この場合、派生クラスで解放が行われないデータが発生可能性があるので、 必ず仮想関数があるクラスのデストラクタではvirtualをつけてください。