基本クラスの仮想継承により、複数の派生クラス間で共通の共有基本クラスが作成され、DDD の問題が解決されることを理解しています。基本クラスの派生クラスが 1 つしかない場合、基本を仮想的に継承する場合と非仮想的に継承する場合に違いはありますか? 基本的には、クエリで提供される説明を理解しようとしていますコンパイル時にクラスからの派生を禁止することは可能ですか? ここで、Usable クラスからの派生を防ぐために、Usage_lock 基本クラスが仮想的に継承されます。この仮想キーを削除すると、動作が変わります。つまり、Usable からサブクラスを派生させることができます。したがって、単一継承シナリオでの仮想キーによる違いの原因を理解したいと思います。
3 に答える
単一の仮想継承の場合の主な違いは、最も派生したクラスのみが仮想的に継承されたベースのコンストラクターを呼び出し、他のすべてのクラスには構築されたクラスへの参照が提供されることです (これは舞台裏で行われます)。
したがって、この例では、さらに派生しようとするUsable
と、新しいクラスがコンストラクター (プライベート) を呼び出す必要Usable_lock
があるため、他のクラスを から派生させることはできませんUsable
。Usable
ロックのフレンドであるため、ロック オブジェクトの作成のみが許可されます。
仮想継承は基本的に、の古典的な問題を解決するために導入されましたDiamond shaped Inheritance
。
次のクラスを検討してください。
class Base {};
class Derived1: Base {};
class Derived2: Base {};
struct MostDerived: Derived1, Derived2 {};
MostDerived
ここのクラスにはBase
、このひし形の階層のために2つのインスタンスがあります。
この問題を解決するために、C ++はキーワードを使用し、仮想継承virtual
と呼ばれる概念を導入します。したがって、ここにキーワード を次
のように追加します。virtual
class Derived1: virtual Base {};
class Derived2: virtual Base {};
Base
これで、 insideMostDerived
クラスのインスタンスが1つだけになるようにします。
そして、クラスはそのコンストラクターを呼び出すことによってクラスMostDerived
のこのインスタンスをインスタンス化します。Base
上記の背景(太字のテキストを強調)を使用して、コード例として次のことを考慮してください。
Usable
クラスは事実上からUsable_lock
派生するため、派生クラスはコンストラクターを呼び出してオブジェクトの基本クラスをインスタンス化するUsable
必要があります。Usable_lock
ただし、Usable_lock
クラスにはプライベートコンストラクターがあるため、クラス自体のみがコンストラクターにアクセスできるため、他のクラスがコンストラクターから派生することはありません。
C ++ 03標準からの参照:
セクション12.6.2ベースとメンバーの初期化
パラグラフ6:
仮想基本クラスを表すすべてのサブオブジェクトは、最も派生したクラス(1.8)のコンストラクターによって初期化されます。最も派生したクラスのコンストラクターが仮想基本クラスVのmem-initializerを指定しない場合、仮想基本クラスサブオブジェクトを初期化するためにVのデフォルトコンストラクターが呼び出されます。Vにアクセス可能なデフォルトのコンストラクターがない場合、初期化の形式は正しくありません。仮想基本クラスに名前を付けるmem-initializerは、最も派生したクラスではないクラスのコンストラクターの実行中に無視されます。
仮想基本クラスは、最も派生したクラスによって構築されます。仮想的に派生させ、そのようなベースのコンストラクターをプライベートにすることにより、別のクラスがそれを構築する方法がなくなるため、実質的に派生を防ぐことができます。ただし、これは非常に人為的な構造であり、オーバーヘッドも伴います。