★デストラクタと継承★


今度はデストラクタ関数の方を確認してみます。

1つサンプルを作って試しましょう。


デストラクタ関数の呼び出し順


<sample program cpp078-01>

#include <iostream>

class Base {
public:

    Base();

    ~Base();
};

class Derived : public Base {
public:

    Derived();

    ~Derived();
};

int main()
{
    Derived derived;

    return 0;
}

Base::Base()
{
    std::cout << "基底クラスのコンストラクタ関数" << std::endl;
}

Base::~Base()
{
    std::cout << "基底クラスのデストラクタ関数" << std::endl;
}

Derived::Derived()
{
    std::cout << "派生クラスのコンストラクタ関数" << std::endl;
}

Derived::~Derived()
{
    std::cout << "派生クラスのデストラクタ関数" << std::endl;
}

<実行結果>

基底クラスのコンストラクタ関数
派生クラスのコンストラクタ関数
派生クラスのデストラクタ関数
基底クラスのデストラクタ関数
続行するには何かキーを押してください・・・

コンストラクタ関数とは逆に「派生クラス」、「基底クラス」の順番でデストラクタ関数が呼び出されました。


注意点


「派生クラス」を「基底クラス」の参照やポインタ変数に入れて使う事はよくある事です。

ただ、気を付けなければならない状況がありますので、それを説明しようと思います。

上のプログラムのmain関数を書き換えましょう。

int main()
{
    Derived *pDerived = new Derived;

    Base *pBase = pDerived;

    delete pBase;

    return 0;
}

まず、「派生クラス」のポインタを用意し、newで領域を確保しました。

「基底クラス」のポインタを用意し、「派生クラス」のアドレスを格納しています。

領域の解放は「基底クラス」で行いました。

「派生クラス」で確保した領域のアドレスを「基底クラス」のポインタに入れていますので、解放されるアドレスは同じような気がします。

実際に実行して結果を見てみましょう。

<実行結果>

基底クラスのコンストラクタ関数
派生クラスのコンストラクタ関数
基底クラスのデストラクタ関数
続行するには何かキーを押してください・・・

「派生クラス」」のデストラクタ関数が呼ばれていません。

確保の時は「派生クラス」で確保しましたが、解放の時は「基底クラス」だったので呼ばれなかったのです。

「派生クラス」のデストラクタに大事なプログラムが書いてあった場合、非常に危険な状態になります。

そこで、これに対応するため↓のようにします。

<sample program cpp078-02>

#include <iostream>

class Base {
public:

    Base();

    virtual ~Base();
};

class Derived : public Base {
public:

    Derived();

    ~Derived();
};

int main()
{
    Derived *pDerived = new Derived;

    Base *pBase = pDerived;

    delete pBase;

    return 0;
}

Base::Base()
{
    std::cout << "基底クラスのコンストラクタ関数" << std::endl;
}

Base::~Base()
{
    std::cout << "基底クラスのデストラクタ関数" << std::endl;
}

Derived::Derived()
{
    std::cout << "派生クラスのコンストラクタ関数" << std::endl;
}

Derived::~Derived()
{
    std::cout << "派生クラスのデストラクタ関数" << std::endl;
}

<実行結果>

基底クラスのコンストラクタ関数
派生クラスのコンストラクタ関数
派生クラスのデストラクタ関数
基底クラスのデストラクタ関数
続行するには何かキーを押してください・・・

「基底クラス」のデストラクタ関数に「virtual」キーワードを付けました。

実行結果を見ると、ちゃんと「派生クラス」のデストラクタ関数が呼ばれています。

このような使い方をする場合、「基底クラス」のデストラクタ関数を「仮想デストラクタ」にしておく必要があります。


次へ

戻る

目次へ