web-dev-qa-db-ja.com

基本仮想デストラクタを明示的に呼び出す必要がありますか?

C++でクラスを(仮想デストラクタで)オーバーライドするとき、継承クラスでデストラクタを仮想として再度実装していますが、ベースデストラクタを呼び出す必要がありますか?

もしそうなら、私はそれがこのようなものだと思います...

MyChildClass::~MyChildClass() // virtual in header
{
    // Call to base destructor...
    this->MyBaseClass::~MyBaseClass();

    // Some destructing specific to MyChildClass
}

私は正しいですか?

313
Nick Bolton

いいえ、デストラクタは構築の逆の順序で自動的に呼び出されます。 (基本クラスが最後です)。基本クラスのデストラクターを呼び出さないでください。

422
Lou Franco

基本デストラクタを呼び出す必要はありません。派生デストラクタによって基本デストラクタが常に呼び出されます。 破壊の順序については、こちらの関連​​する回答をご覧ください

基本クラスに仮想デストラクタが必要な理由を理解するには、以下のコードを参照してください。

class B
{
public:
    virtual ~B()
    {
        cout<<"B destructor"<<endl;
    }
};


class D : public B
{
public:
    virtual ~D()
    {
        cout<<"D destructor"<<endl;
    }
};

あなたがするとき:

B *pD = new D();
delete pD;

次に、Bに仮想デストラクタがない場合、〜B()のみが呼び出されます。ただし、仮想デストラクタがあるため、最初に〜D()が呼び出され、次に〜B()が呼び出されます。

86
Brian R. Bondy

他の人が言ったことですが、派生クラスで仮想デストラクタを宣言する必要がないことにも注意してください。基本クラスで行うように、デストラクタを仮想で宣言すると、すべての派生デストラクタは、宣言するかどうかにかかわらず仮想になります。言い換えると:

struct A {
   virtual ~A() {}
};

struct B : public A {
   virtual ~B() {}   // this is virtual
};

struct C : public A {
   ~C() {}          // this is virtual too
};
26
anon

いいえ。DerivedからBaseメソッドを明示的に呼び出して呼び出しを「チェーン」する他の仮想メソッドとは異なり、コンパイラーは、コンストラクターが呼び出された順序と逆の順序でデストラクターを呼び出すコードを生成します。

10
itsmatt

いいえ、基本クラスのデストラクタを呼び出すことはありません。他の人が指摘したように常に自動的に呼び出されますが、結果の概念実証は次のとおりです。

class base {
public:
    base()  { cout << __FUNCTION__ << endl; }
    ~base() { cout << __FUNCTION__ << endl; }
};

class derived : public base {
public:
    derived() { cout << __FUNCTION__ << endl; }
    ~derived() { cout << __FUNCTION__ << endl; } // adding call to base::~base() here results in double call to base destructor
};


int main()
{
    cout << "case 1, declared as local variable on stack" << endl << endl;
    {
        derived d1;
    }

    cout << endl << endl;

    cout << "case 2, created using new, assigned to derive class" << endl << endl;
    derived * d2 = new derived;
    delete d2;

    cout << endl << endl;

    cout << "case 3, created with new, assigned to base class" << endl << endl;
    base * d3 = new derived;
    delete d3;

    cout << endl;

    return 0;
}

出力は次のとおりです。

case 1, declared as local variable on stack

base::base
derived::derived
derived::~derived
base::~base


case 2, created using new, assigned to derive class

base::base
derived::derived
derived::~derived
base::~base


case 3, created with new, assigned to base class

base::base
derived::derived
base::~base

Press any key to continue . . .

基本クラスデストラクタを仮想クラスとして設定すると、ケース3の結果はケース1および2と同じになります。

7
zar

いいえ。自動的に呼び出されます。

6
Benoît