次の例を考えます。
class BaseClass
{
BaseClass()
{
};
virtual ~BaseClass()
{
this->Cleanup();
};
virtual void Cleanup()
{
// Do cleanup here.
};
};
class Level1DerivedClass : public BaseClass
{
Level1DerivedClass()
{
};
virtual ~Level1DerivedClass()
{
};
virtual void Cleanup()
{
// Call my base cleanup.
BaseClass::Cleanup();
// Do additional cleanup here.
};
};
class Level2DerivedClass : public Level1DerivedClass
{
Level2DerivedClass()
{
};
~Level2DerivedClass()
{
};
void Cleanup()
{
// Call my base cleanup.
Level1DerivedClass::Cleanup();
// Do additional cleanup here.
};
};
main()
{
Level2DerivedClass * derived2 = new Level2DerivedClass();
delete derived2;
return 0;
}
派生クラス参照を削除すると、フローは次のようになると予想されます。
- Level2DerivedClassデストラクタが実行されます。
- Level1DerivedClassデストラクタは仮想であるため、実行されます。
- BaseClassデストラクタは仮想であるため、実行されます。
- BaseClass ::CleanupとLevel1DerivedClass::Cleanupはどちらも仮想であるため、 BaseClassデストラクタのBaseClass'this 'ポインタからの呼び出しは、最も派生したクラスであるLevel2DerivedClass::Cleanupの実装を実行します。
- Level2DerivedClass :: Cleanupは、その親のCleanup実装を呼び出します。
- Level1DerivedClass :: Cleanupは、その親のCleanup実装を呼び出します。
何が起こっているのかというと、私が期待している方法よりも、継承の各レベル(1〜3)のデストラクタを呼び出しているということです。ただし、this-> Cleanup()がBaseClassデストラクタから呼び出されると、独自の実装のみが実行されます。通常、派生クラスポインターをインスタンス化し、それを基本クラスポインターとしてキャストし、基本クラスポインター(この場合は「this」)から仮想メソッドを呼び出すと、これが発生する理由がわかりません。派生クラスの実装(「仮想」の要点ですよね?)。私の例では、Level2DerivedClass::CleanupとLevel1DerivedClass::Cleanupが呼び出されることはありません。
このように設定する理由は、オブジェクトを破棄せずにクリーンアップコードを呼び出せるようにするためです。そのため、実際のデストラクタ本体からオブジェクトを抽象化しています。
これを行うためのより適切な方法についての提案があれば、私はすべての耳です。しかし、セットアップが機能しない理由についても説明したいと思います。何を誤解しているのでしょうか。
よろしくお願いします。