2009-03-24 7 views
267

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

ので、私はそれがこのようなものだと想像した場合...

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

    // Some destructing specific to MyChildClass 
} 

は、私は右ですか?

答えて

365

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

+0

純粋仮想デストラクタはどうですか?私のリンカは、継承されたクラスの非仮想デストラクタの終わりにそれを呼び出そうとしています。 – cjcurrie

+32

ボディを持たない純粋な仮想デストラクタを持つことはできません。ただそれに空の体を与えてください。通常の純粋仮想メソッドでは、オーバーライド関数が代わりに呼び出され、デストラクタとともに呼び出されます。したがって、本体を用意する必要があります。 = 0は、それがオーバーライドされなければならないことを意味します。したがって、必要な場合には便利なコンストラクトです。 –

+1

この質問は関連し、[質問/ 15265106/c-a-missing-vtable-error](http://stackoverflow.com/questions/15265106/c-a-missing-vtable-error)と関連している可能性があります。 –

80

ベースデストラクタを呼び出す必要はありません。ベースデストラクタは、常に派生デストラクタによって呼び出されます。 Please see my related answer here for order of destruction

あなたは、基本クラスで仮想デストラクタをしたい理由を理解するには、以下のコードを参照してください:あなたが行うと

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()が呼び出されます。

+12

プログラム(疑似)出力を含めてください。それは読者を助けるでしょう。 –

6

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

25

派生クラスでデストラクタバーチャルを宣言する必要はありません。デストラクタ仮想を宣言すると、基本クラスの場合と同様に、宣言したかどうかにかかわらず、派生したすべてのデストラクタは仮想になります。言い換えれば、明示的に呼び出し「鎖」に派生からベースメソッドを呼び出すことになる他の仮想メソッドとは異なり

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

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

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

〜Bが仮想宣言されていない場合はどうなりますか? 〜Cはまだ仮想ですか? – Will

+4

はい。仮想メソッド(デストラクタだけでなく)が仮想宣言されている場合、派生クラスのそのメソッドのすべてのオーバーライドは自動的に仮想になります。この場合、たとえあなたが〜B仮想を宣言しなくても、それはまだありますし、〜Cもそうです。 – boycy

+1

しかし、基本クラスの対応するメソッドの同じ名前とパラメータを持つ他のオーバーライドされたメソッドとは異なり、デストラクタの名前は異なります。重要ですか? @Boycy –

9

号は、コンパイラは、逆の順序でデストラクタを呼び出すコードを生成しますそのコンストラクタが呼び出されました。

2

いいえ、あなたはbeseクラスのデストラクタを呼び出すことはありません、それは常に他の人のように自動的に呼び出されるが指摘したが、ここでの結果とのコンセプトの証明ですしている:

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 . . . 

基本クラスのデストラクタを仮想として設定した場合、結果はケース1と同じです。& 2.

関連する問題