1. ホーム
  2. c++

[解決済み] 仮想デストラクタは継承されるのか?

2023-07-20 08:43:42

質問

仮想デストラクタを持つ基底クラスがある場合、派生クラスも仮想デストラクタを宣言する必要がありますか?派生クラスも仮想デストラクタを宣言しなければならないのでしょうか?

class base {
public:
    virtual ~base () {}
};

class derived : base {
public:
    virtual ~derived () {} // 1)
    ~derived () {}  // 2)
};

具体的な質問

  1. 1)と2)は同じですか?2)はベースがあるので自動的に仮想化されるのか、それとも仮想化を"stop"するのでしょうか?
  2. 派生したデストラクタは、何もしなければ省略できるのでしょうか?
  3. 派生デストラクタを宣言するためのベストプラクティスは何ですか?virtual、non-virtual、可能なら省略のどれを宣言しますか?

どのように解決するのですか?

  1. はい、同じです。 派生クラスが何かを virtual 宣言しなくても、それが virtual であることを止めることはできません。 実際、ベースクラスで仮想化されていたメソッド(デストラクタを含む)を派生クラスで仮想化しないようにする方法はありません。C++11では、次のように記述します。 final を使用して、派生クラスでオーバーライドされるのを防ぐことができますが、それは仮想であることを防ぐものではありません。
  2. はい、派生クラスのデストラクタは、何もすることがなければ省略することができます。 そして、その仮想かどうかは問題ではありません。
  3. 私は可能なら省略します。 そして、私はいつもどちらかの virtual キーワードか override を使用することで、派生クラスの仮想関数を明確にすることができます。 関数が仮想であることを理解するために、わざわざ継承階層を上がっていく必要はないはずです。さらに、クラスがコピーや移動が可能な場合、独自のコピーや移動のコンストラクタを宣言する必要はなく、何らかのデストラクタを宣言する(たとえ default として定義していても) デストラクタを宣言すると、コンパイラはコピーと移動のコンストラクタと代入演算子を入れてくれないので、必要であれば宣言しなければならなくなります。

項目 3 の小さなポイントとして。 デストラクタが未宣言の場合、コンパイラはデフォルトのものを生成することがコメントで指摘されています (それはまだ仮想です)。 そして、そのデフォルトのものはインライン関数です。

インライン関数は潜在的に、プログラムの他の部分の変更に対してより多くのプログラムを公開し、共有ライブラリのためのバイナリ互換性をトリッキーにします。 また、結合の増加により、ある種の変更に直面して多くの再コンパイルが必要になることがあります。 例えば、仮想デストラクタの実装が本当に必要だと判断した場合、それを呼び出すコードのすべての部分を再コンパイルする必要があります。 一方、クラスのボディで宣言した後、それを .cpp ファイルで空にしておけば、再コンパイルせずに変更しても問題ないでしょう。

私の個人的な選択は、可能な限り省略することです。 私の意見では、コードが乱雑になり、コンパイラーは空の実装よりもデフォルトの実装でわずかに効率的なことを行うことができます。 しかし、それが悪い選択となるような制約がある場合もあります。