仮想継承は、クラスが から継承する場合にのみ関連し
Foo
ます。次のように定義すると:
class B {};
class L : virtual public B {};
class R : virtual public B {};
class D : public L, public R {};
その場合、最終的なオブジェクトには、 と の両方で共有される のコピーが 1 つだけ含まれB
ます
。がなければ、タイプ のオブジェクトには の2 つのコピーが含まれ、1 つはに、もう 1 つは に含まれます。L
R
virtual
D
B
L
R
すべての継承は仮想でなければならないという議論があります (それが違いを生む場合、ほとんどの場合、それが必要になるためです)。ただし、実際には、仮想継承は高価であり、ほとんどの場合、必要ありません。適切に設計されたシステムでは、ほとんどの継承は、1 つまたは複数の「インターフェイス」から継承する具体的なクラスのものになります。このような具象クラスは通常、それ自体から派生するようには設計されていないため、問題はありません。ただし、重要な例外があります。たとえば、インターフェイスを定義してからインターフェイスの拡張を定義する場合、具体的な実装では複数の拡張を実装する必要があるため、拡張は基本インターフェイスから仮想的に継承する必要があります。または、特定のクラスがインターフェースの一部のみを実装する mixin を設計している場合、最終的なクラスは、これらのクラスのいくつかを継承します (インターフェイスのパーツごとに 1 つ)。最後に、実質的に継承するかどうかの基準はそれほど難しくありません。
いくつかの例外がありますが、上記の規則は安全性の面で誤りです。仮想継承が必要ない場合でも、通常は仮想継承が「正しい」です。
最後のポイント: 仮想ベースは、直接継承する (そして継承が仮想であることを宣言する)クラスではなく、常に最も派生したクラスによって初期化する必要があります。ただし、実際には、これは問題ではありません。仮想継承が理にかなっているケースを見ると、それは常にインターフェイスから継承するケースであり、データが含まれていないため、デフォルトのコンストラクター (のみ) があります。引数を取るコンストラクターを使用してクラスから仮想的に継承していることに気付いた場合は、設計についていくつかの深刻な質問をする時が来ました。