したがって、ダイヤモンド継承の問題があり、仮想継承を行うと、基本クラスの1つだけが作成されることを理解していますが、これはどのように正確に表現されていますか?
vtableには基本クラスへのポインタがあり、派生クラスの1つが構築されると、そのポインタがすでに存在するかどうかを確認し、存在しない場合はそれを作成して基本クラスを指すようにしますか?
したがって、ダイヤモンド継承の問題があり、仮想継承を行うと、基本クラスの1つだけが作成されることを理解していますが、これはどのように正確に表現されていますか?
vtableには基本クラスへのポインタがあり、派生クラスの1つが構築されると、そのポインタがすでに存在するかどうかを確認し、存在しない場合はそれを作成して基本クラスを指すようにしますか?
あなたは正しく始めます。実装の詳細は異なる場合がありますが、実際には、基本クラスを見つけるのに十分な情報が vtable (またはクラス メタデータ) にあります。
2番目の部分については、どの実装にも「ポインターが既に存在するかどうかを確認する」ことはありません。C++ では、最も派生したクラスがすべての仮想ベースの構築を担当します。Root
したがって、 、Middle1
、Middle2
およびを含む通常のダイヤモンド継承では、 willMostDerived
のインスタンスを構築するために発行されるコードは次のようになります。MostDerived
Root
して設定し、vtable を指すようにします。MostDerived
Middle1
し、Middle2
MostDerived
MostDerived
「vptr」ではなく「vptr」と言います。これはMiddle1
、Root
基本クラスの構築中に利用可能ですが、 の仮想関数は で定義されたオーバーライドをまだ参照してMiddle1
いないMostDerived
ためです。Middle1
これを整理するのは実装次第です。オブジェクトのサイズを調べて、それを行うために使用される隠しポインターの数と、その数が仮想関数があるかどうかに依存するかどうかを自分で試すことができます。
のインスタンスを構築するために発行される通常のコードは次のようにMiddle1
なることに注意してください。
Root
して設定し、vtable を指すようにします。Middle1
Middle1
Middle1
ます。Middle1
の基底クラスのサブオブジェクトを構築するときはMostDerived
、これらの手順のうち 3 つすべてではなく 2 つだけを実行する必要があります。このため、複数のコンストラクターを持つクラスの発行されたコードには、複数のコンストラクターが含まれていることがわかるでしょう。1 つは、最も派生した型がクラスであるオブジェクト用であり、別のコンストラクターは、型がクラスである基本クラスのサブオブジェクト用です。 .