2014年1月29日水曜日

C++ デストラクタを仮想関数にする


いつものPCが不調につき。

開発者の手助けとなるツールにEclipseという

ものがあります。

IDE(Integrated Development Environment)

なのでデバッグもできてしまいます。




GUIでの簡単な操作、しかも無料で使えるというのは本当に素晴らしいですね!

さて、本題に入ります(^_^;)

継承する可能性のあるクラスのデストラクタは、仮想関数にしてください。

今、基底クラスのポインタが、その基底クラスから派生したクラスの

オブジェクトを指している場合を考えてみます。

基底クラスのデストラクタが仮想関数でない場合、基底クラスのポインタに対して

delete を実行すると、なんと派生クラスのデストラクタが呼ばれないのです(>_<)

したがって、派生クラスのデストラクタ内でメモリの解放をしているような場合、

基底クラスのポインタから delete を実行しても、そのメモリが解放されないという

困った現象が起きてしまいます(-_-;)

とある実行結果
# ./test
I'm Vegetable::SetPrice()
Price = I'm Vegetable::GetPrice()
398
I'm ~Food()

これを回避するためには、次のように基底クラスのデストラクタを

仮想関数にしておくことで、派生クラスのデストラクタが呼ばれるようになります。

class Food {
public:
    Food();
    virtual ~Food();    //デストラクタを仮想関数にしています
        :

とある実行結果2
# ./test
I'm Vegetable::SetPrice()
Price = I'm Vegetable::GetPrice()
I'm ~Vegetable()
I'm ~Food()

メモリリークが原因で、突然プログラムが落ちてしまうという問題は、

何が原因かを特定するまで難航することがあります(?_?)

こだわりを持って、品質のいいソフトウェア開発ができるようにしたいものです。

こんな使い方はしなさそうな、今回の状況を試すためのサンプル
include <iostream>

using namespace std;

class Food
{
public:
    //~Food();      こちらでは派生クラスのデストラクタが呼ばれません
    virtual ~Food();      //こちらは実行結果2のほうになります
    void SetPrice(int price);
    int GetPrice(void);
private:
    int m_price;
};

class Vegetable : public Food
{
public:
    ~Vegetable();
    void SetPrice(int price);
    int GetPrice(void);
private:
    int m_price;
    int *m_ptr;
};

Food::~Food()
{
    cout << "I'm ~Food()" << endl;
}

oid Food::SetPrice(int price)
{
    cout << "I'm Food::SetPrice()" << endl;
    m_price = price;
}

int Food::GetPrice(void)
{
    cout << "I'm Food::GetPrice()" << endl;
    return m_price;
}

Vegetable::~Vegetable()
{
    cout << "I'm ~Vegetable()" << endl;
    if (m_ptr != NULL) { delete m_ptr; m_ptr = NULL; }
}

nt Vegetable::GetPrice(void)
{
    cout << "I'm Vegetable::GetPrice()" << endl;
    return m_price;
}

int main(void)
{
    Vegetable *pmyVegetable = new Vegetable;
    Food *pmyFood = pmyVegetable;

    pmyVegetable->SetPrice(398);
    cout << "Price = " << pmyVegetable->GetPrice() << endl;

    delete pmyFood;

    return 0;
}


今日の名言
苦境に立って万事休した時には、できることがあれば、それをやる。できることが
なければ、あとは忘れるだけだ。私は未来について決して心配しない。未来に
どんなことが起きるかを予想できる人などいないからだ。未来に影響を及ぼす力は
実にたくさんある!それらの力を動かすものが何であるのか誰も知らないし、
その力自体も理解できない。なのに、どうして悩むのだ。
                                K・T・ケラー

人を憎むのは、ネズミ一匹追い出すために、家全体を焼き払うようなものだ。
                         ハリー・エマーソン・フォデスディック

私は一文無しになっても悩みはしないだろう。悩んだところで何の益もないからだ。
私は最善を尽くして、あとの結果は神におまかせする。
                                J・C・ペニー