親クラスには仮想関数があります。親クラスに仮想デストラクタが必要ですか?
質問は1です。3つのルールを考えて、他の2つを宣言する必要がありますか?
A virtual destructor is required any time delete
is called on a pointer to that class where the object being deleted is actually of a more derived type. If your base class may be used in this sort of situation then you must provide a virtual destructor.
It is usually advisable to add a virtual destructor to any class that has virtual functions as this gives safety and flexibility to future users of the class and the additional cost of adding a virtual destructor to an already polymorphic class is typically low.
This last rule is just a rule of thumb, though. It may be necessary to have a virtual destructor in a class even if it doesn't have any other virtual functions and, conversely, a virtual destructor may not be needed for a polymorphic class if it is never used in a context that requires this (typically the destructor would be made protected
or even private
to enforce this).
You only need to provide a user-defined copy constructor and a copy assignment operator if the compiler provided default implementations won't do the correct thing. If you've added a destructor with an empty implementation purely to make it virtual, this is unlikely to have any bearing on the need for you to provide a copy constructor and a copy assignment operator.
仮想関数を持つクラスが仮想デストラクタを持つことは理にかなっています。これは、継承され、多形的に使用される可能性が高いクラスであるためです(関連するSOの質問を参照)。また、親クラスへのポインタが派生型のインスタンスを指すという意味で、多態的に使用される場合、親クラスには仮想デストラクタが必要です。
一方、親のクラスデストラクタが、コンパイラで合成されたものでは実行できないことを実際に実行した場合(たとえば、一部のリソースの解放を明示的に処理する場合)は、親の3つのルールに従う必要があります。親のデストラクタが自明であり、親クラスポインタからのポリモーフィックオブジェクトの正しい破棄を許可するように宣言されている場合は、そのコピーコンストラクタとコピー割り当て演算子を提供する必要はありません。
クラスに仮想デストラクタを含める唯一の本当の理由は、そのクラスのオブジェクトを多態的に削除することを計画している場合、つまり、delete
基本クラスへのポインタを介して派生クラスのオブジェクトを削除することを計画している場合です。それを行わない場合は、仮想デストラクタは必要ありません。
ただし、クラスにすでに仮想関数がある場合は、デストラクタを仮想化しても、感知できるほどのオーバーヘッドは発生しません(VMTポインタがオブジェクトにすでに導入されているため)。このような状況では、デストラクタを仮想化することをお勧めします。念のため。
技術的には、インスタンスを多態的に削除する場合にのみ、仮想デストラクタが必要です。つまり、仮想デストラクタがなくても仮想メソッドを使用できます。
ただし、実用的な観点から、デストラクタを仮想として宣言しない理由はめったにありません。これは、ベースとして使用できると思われるクラスに対して行う必要があります。
3つのルールは、プログラムロジックについて話します。デストラクタ、コピーコンストラクタ、または割り当てのいずれかにロジックがある場合は、おそらく3つすべてにロジックが必要です。ただし、これは正式な観点からは厳密な規則ではなく、単純に保持されない場合がまれにあることに注意してください(たとえば、作成されたすべてのオブジェクトのログに行を表示することに興味があるかもしれませんが、割り当てについてはそうではありません)または破壊)。
また、私の経験では、継承とポリモーフィズムがある場合、C++のコピーセマンティックや静的型付けでさえ正しく感じられない場合があることにも注意してください。
ある時点で基本クラスになる可能性のあるクラスはすべて、デストラクタが仮想として宣言されている必要があります。別のメンバー関数が仮想であるかどうかに関係なく。
三つのルールはあなたが宣言するべきだと言っています
それらの1つを宣言した場合。破壊が仮想的であるかどうかとは無関係に。