あなたが言うように、継承は「解決」する必要はないので、質問はあまり明確ではありません。
重要な違いは、通常の継承と仮想継承の違いです。通常、つまり を継承する場合B : A
、C : A
クラスD : B, C
にはタイプ の2 つのサブクラスA
、つまりD::B::A
とがありD::C::A
ます。一方、 が実質的に から継承する場合B
、最終的な型を定義するまで、最終的なサブクラスの構成は延期されます。つまり、とのいずれかをインスタンス化すると、それ自体が実体となる仮想サブクラスを持っています。一方、クラスからさらに派生する場合、最も派生したクラスには type のサブクラスが1 つだけ含まれます。C
A
B : virtual A
C : virtual A
A
B
C
A
おそらく、メンバー関数との類推を検討したいかもしれません。各派生クラスが基本関数と同じ名前のメンバー関数を追加すると、いくつかの異なる関数が作成されます。一方、基本関数が の場合、最も派生したクラスで定義されている関数は1 つvirtual
しかありません。各中間クラスにはまだある種の関数がありますが (関数が純粋仮想ではない場合)、「アクティブな」定義を定義するのは最終クラスだけです。
仮想継承はコンストラクターに影響を与えます。つまり、仮想ベース コンストラクター (例の場合) は、またはではなく、最も派生したクラス (つまり、A()
) によって直接呼び出されます。もしそうなら、これは、サブクラスが1つしか含まれていないことを「知っている」ためであり、直接「責任を負う」からです。究極の最も派生したクラスに道を譲る仮想プレースホルダーを保持するだけです。D
B
C
D
A
B
C
基本ポインタ/参照を介してメンバー関数にアクセスすると、期待どおりに動作し、通常の方法で (つまり、一般に動的に) 解決されますが、これは仮想継承とは関係ありません。実際の関数ルックアップは、余分なレベルの間接参照が含まれる可能性があるため、もう少し複雑になる可能性がありますが、基本的なことは何も変わりません。