class A {
int i;
};
class B : public A {
int j;
};
仮想継承を使用しないこの例では、次のように定義されているかのように、タイプのオブジェクトをBレイアウトできます。B
class B0 {
int i;
int j;
};
仮想継承を導入すると、これは機能しません。
class C : public virtual A {
int k;
};
class D : public virtual A {
int l;
};
class E : public C, public D {
int m;
};
タイプのオブジェクトには、の定義からとの定義からのC2つのintメンバーがあります。同様に、タイプのオブジェクトには2つのメンバーとがあります。ここまでは順調ですね。トリッキーな部分にはクラスがあります。の両方のインスタンスが仮想ベースであるため、クラスにも1つのメンバーがあります。したがって、上記のように書くこともできません。これは、のコピーが2つになるためです。kCiADintliE intiACDB0Ei
解決策は、間接参照のレイヤーを追加することです。Cタイプ、、のオブジェクトは次のようDになりEます(擬似コード、コンパイルしないでください)。
class C0 {
int *cip = &i;
int k;
int i;
};
class D0 {
int *dip = &i;
int l;
int i;
};
class E0 {
// C0 subobect:
int *cip = &i;
int k;
// D0 subobject:
int *dip = &i;
int l;
// E data:
int *eip = &i;
int m;
int i;
};
のサイズで表示されているのは、これらの追加のポインターです。これにより、方法に関係なく、派生クラスで結合されたEの単一のコピーを持つことができます。(実際には、これらの各ポインターは、へのポインターになります。これは、確かに複数のデータメンバーを持つことができるためですが、この単純な擬似コードで表すのは難しすぎます)。iCDAA