web-dev-qa-db-ja.com

デストラクタはいつ仮想化する必要がありますか?

重複の可能性:
仮想デストラクタをいつ使用するか?

C++オブジェクトのデストラクタはいつvirtualにする必要がありますか?

42
Michael Zhou
  1. クラスメソッドの少なくとも1つが仮想である場合、仮想デストラクタが必要です。

これは、仮想メソッドの理由は、ポリモーフィズムを使用したいためです。つまり、基本クラスポインターでメソッドを呼び出し、最も派生した実装が必要です。これがポリモーフィズムの要点です。

ここで、仮想デストラクタがなく、基本クラスへのポインタを介してdestructorを呼び出すと、最終的に基本クラスのデストラクタを呼び出すことになります。この場合、ポリモーフィズムをデストラクタでも機能させる必要があります。基本クラスでデストラクタを呼び出すことにより、基本クラスではなく、最も派生したクラスのデストラクタを呼び出すことになります。

class A
{
   virtual void f() {}
   ~A() {}
}

class B : public A
{
   void f() {}
   ~B() {}
}

A * thing = new B();
thing->f(); // calls B's f()
delete thing; // calls ~A(), not what you wanted, you wanted ~B()

〜A()仮想を持つことでポリモーフィズムがオンになります

virtual ~A() {}

だからあなたが今電話するとき

delete thing;

〜B()が呼び出されます。

クラスをインターフェイスとして設計するときに、仮想デストラクタを宣言します。あなたはそれが拡張または実装されることを期待しています。その場合の良い習慣は、仮想メソッドと仮想デストラクタを備えたインターフェイスクラス(Javaインターフェイスの意味で))を用意してから、具体的な実装クラスを用意することです。

STLクラスには仮想デストラクタがないため、拡張されることは想定されていないことがわかります(例:std :: vector、std :: string ...)。 std :: vectorを拡張し、ポインタまたは参照を介して基本クラスのデストラクタを呼び出す場合、メモリリークにつながる可能性のある特殊なクラスデストラクタを絶対に呼び出さないでしょう。

53
stefanB

から StroustrupのC++スタイルとテクニックに関するFAQ

では、いつデストラクタを仮想として宣言する必要がありますか?クラスに少なくとも1つの仮想関数があるときはいつでも。仮想関数を持つことは、クラスが派生クラスへのインターフェイスとして機能することを意図していることを示します。その場合、派生クラスのオブジェクトは、ベースへのポインタを介して破棄される可能性があります。

デストラクタがC++ FAQで仮想である必要がある場合 に関する多くの追加情報。 (Stoborに感謝)

仮想メンバーとは何ですか? C++ FAQ から:

[20.1]「仮想メンバー関数」とは何ですか?

OOの観点からは、C++の最も重要な機能は[6.9]、[6.10]です。

仮想関数を使用すると、派生クラスで基本クラスによって提供される実装を置き換えることができます。コンパイラーは、オブジェクトが派生ポインターではなく基本ポインターによってアクセスされる場合でも、問題のオブジェクトが実際に派生クラスである場合は常に、置換が常に呼び出されるようにします。これにより、ユーザーが派生クラスについて知らなくても、基本クラスのアルゴリズムを派生クラスで置き換えることができます。

派生クラスは、基本クラスのメンバー関数を完全に置き換える(「オーバーライド」)か、派生クラスが基本クラスのメンバー関数を部分的に置き換える(「拡張」)ことができます。後者は、必要に応じて、派生クラスのメンバー関数に基本クラスのメンバー関数を呼び出させることによって実現されます。

33
luke

私は最近、完全に正しい答えはこれであると結論付けるようになりました:

ガイドライン#4:基本クラスのデストラクタは、パブリックで仮想、または保護されて非仮想である必要があります。

そしてもちろん ハーブサッターは理論的根拠を与えます 彼の主張に。彼は「誰かが基本クラスのポインタを介して派生クラスのオブジェクトを削除するとき」と「クラスに仮想関数がある場合はデストラクタを仮想にする」という通常の答えを超えていることに注意してください。

5
Reunanen

基本クラスポインタを介して派生クラスのオブジェクトを破棄する(または破棄する可能性がある)場合は、仮想デストラクタが必要です。

クラスAT ALLから派生する場合は、仮想デストラクタが必要であるというアプローチを取ります。私が記述したコードには、パフォーマンスに影響を与えるケースは事実上ありません。仮想デストラクタは重要であり、今日は実際には必要ありませんが、クラスが変更されると、将来必要になる可能性があります。

基本的に:十分に考え抜かれた理由がない限り、すべての基本クラスのデストラクタに仮想を配置します。

これはもう1つの経験則ですが、後で間違いを犯さないようにするためのものです。

3
Michael Kohne

常に。

Vtableのストレージとパフォーマンスのオーバーヘッドに本当に関心がない限り、私は常にそれを仮想化します。デストラクタが適切な場合に仮想であることを確認する静的分析ツールがない限り、間違いを犯して、必要なときに仮想デストラクタを作成しないことは価値がありません。

0
Jared Oberhaus