54

finalJava と C# は、 andsealedキーワードを使用して基本クラスとして使用できないクラスの概念をサポートしています 。しかし、C++ では、クラスの作成者にジレンマを残すクラスの派生を防ぐ良い方法はありません。すべてのクラスに仮想デストラクタがあるべきかどうか?


編集: C++11 以降、これは当てはまらないため、クラスが であることを指定できますfinal


一方では、オブジェクトに仮想デストラクタを与えることはvtablevptr.

一方、後で誰かがこのクラスから派生し、基本クラスへのポインターを介して派生クラスを削除した場合、プログラムは (仮想デストラクタがないため) 不適切に定義され、率直に言って、オブジェクトごとのポインターを最適化することはばかげている。

仮想デストラクタを持つ握り手で(おそらく)、この型が多態的に使用されることを意図していることをアドバタイズします。

仮想デストラクタを使用しない明確な理由が必要だと考える人もいれば (この質問のサブテキストのように)、クラスが派生すると信じる理由がある場合にのみ仮想デストラクタを使用する必要があると言う人もいます。考える?

4

7 に答える 7

58

すべての抽象クラスには、

  • 保護されたデストラクタ、または、
  • 仮想デストラクタ。

公開された非仮想デストラクタを使用している場合、ユーザーはそのポインターを介して派生オブジェクトを削除できるため、これは適切ではありません。私たち全員が知っているように、それは未定義の動作です。

抽象クラスの場合、オブジェクトに仮想テーブル ポインターが既に必要なので、virtual(私が知る限り) デストラクタを作成しても、スペースや実行時のパフォーマンスの点でコストが高くなりません。また、派生クラスには自動的にデストラクタがあるという利点がありますvirtual(@Aconcagua のコメントを参照)。もちろん、protected virtualこの場合のデストラクタを作成することもできます。

ポインターを介して削除されることを意図していない非抽象クラスの場合、仮想デストラクタを使用する正当な理由はないと思います。リソースを浪費しますが、さらに重要なことに、ユーザーに間違ったヒントを与えることになります。std::iterator仮想デストラクタを与えるとどんな奇妙な意味があるのか​​考えてみてください。

于 2008-12-09T19:06:36.300 に答える
31

問題は本当に、クラスの使用方法に関する規則を適用したいですか? なんで?クラスに仮想デストラクタがない場合、そのクラスを使用する人は誰でも、それが派生することを意図していないこと、およびとにかくそれを試した場合に適用される制限を知っています。それでいいんじゃない?

それとも、誰かがあなたが予期していなかったことを敢えてやろうとした場合に、コンパイラがハードエラーをスローする必要がありますか?

人々がそれから派生することを意図している場合は、クラスに仮想デストラクタを与えます。それ以外の場合は、コードを使用する人は誰でもコードを正しく使用するのに十分な知性を持っていると想定してください。

于 2008-12-09T19:18:58.647 に答える
8

いいえ!仮想デストラクタは、派生クラスのオブジェクトが基底クラス ポインタによって削除される場合にのみ使用されます。クラスがこのシナリオのベースとして機能することを意図していない場合は、デストラクタを仮想にしないでください。間違ったメッセージを送信することになります。

于 2008-12-09T19:04:09.597 に答える
5

Herb Sutter のこの記事をチェックしてください:

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

于 2008-12-10T13:08:24.947 に答える
2

一般的な質問には「いいえ」と答えます。すべてのクラスに必要なわけではありません。クラスが継承されるべきではないことがわかっている場合は、わずかなオーバーヘッドが発生する必要はありません。しかし、機会があれば、安全な側にいて、そこに置いてください.

于 2008-12-09T18:58:23.977 に答える
1

基本クラスは、少なくとも 1 つの純粋仮想関数を含む場合、抽象クラスになります。Base に仮想デストラクタがなく、Derived (Base から派生したもの) がある場合、Derived オブジェクト ポインターを介して Derived オブジェクトを安全に破棄できますが、Base オブジェクト ポインターを介しては破棄できません。

于 2010-05-12T20:04:36.073 に答える
0

親クラスまたは子クラスで仮想を忘れたときにデストラクタが呼び出されないことにしばらく頭を悩ませたことがあることを付け加えておきます。私は今それを探すことを知っていると思います。:)

親クラスがデストラクタで子がすべきではないことをする場合があると主張する人もいるかもしれませんが、それはおそらく継承構造に何か問題があることを示しています。

于 2008-12-09T19:14:19.827 に答える