web-dev-qa-db-ja.com

すべてのクラスに仮想デストラクタが必要ですか?

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


Edit:これはC++ 11には当てはまらないため、クラスが final であることを指定できます。 =。


一方、オブジェクトに仮想デストラクタを与えることは、vtableを持つため、vptrのオブジェクトごとに4(または64ビットマシンでは8)追加バイトを消費することを意味します。

一方、誰かが後でこのクラスから派生し、基本クラスへのポインタを介して派生クラスを削除した場合、プログラムは(仮想デストラクタが存在しないために)不明確になり、オブジェクトごとのポインタの率直な最適化はとんでもない。

グリップハンド では、仮想デストラクタが(ほぼ間違いなく)このタイプが多態的に使用されることを意図していることを宣伝しています。

仮想デストラクタを使用しない明示的な理由が必要であると考える人もいます( この質問 のサブテキストのように)、クラスがそうであると信じる理由がある場合にのみ使用するべきだと言う人もいますyouはどう思いますか?

49
Motti

問題は本当に、クラスをどのように使用すべきかについての規則をenforceにしたいですか?どうして?クラスに仮想デストラクタがない場合、そのクラスを使用する人はだれでも派生することを意図していないことを知っており、とにかく試してみるとどのような制限が適用されます。それでは十分ではありませんか?

または、誰かが予期しない何かをするためにdaresの場合、ハードエラーをスローする必要がありますか?

人々に派生させたい場合は、クラスに仮想デストラクタを与えます。そうでなければ、コードを使用している人はコードを正しく使用するのに十分な知性を持っていると想定してください。

28
jalf

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

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

パブリックな非仮想デストラクタを持っている場合、ユーザーはそのポインタを介して派生オブジェクトを削除できるため、これは役に立ちません。誰もが知っているように、それは未定義の動作です。

クラスへのポインタを介して削除することを意図していないクラスの場合、仮想デストラクタを持つ理由はまったくありません。リソースを無駄にするだけでなく、さらに重要なことは、ユーザーに間違ったヒントを与えることです。 std::iterator仮想デストラクタ。

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

8

ハーブサッターのこの記事 を確認してください。

ガイドライン#4:基本クラスのデストラクターは、パブリックおよび仮想、または保護された非仮想でなければなりません。

4
Paolo Tedesco

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

2
Evan Teran

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

1
shurli pataka

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

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

0
Patrick Hogan