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;
};
タイプのオブジェクトには、の定義からとの定義からのC
2つのint
メンバーがあります。同様に、タイプのオブジェクトには2つのメンバーとがあります。ここまでは順調ですね。トリッキーな部分にはクラスがあります。の両方のインスタンスが仮想ベースであるため、クラスにも1つのメンバーがあります。したがって、上記のように書くこともできません。これは、のコピーが2つになるためです。k
C
i
A
D
int
l
i
E
int
i
A
C
D
B0
E
i
解決策は、間接参照のレイヤーを追加することです。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
の単一のコピーを持つことができます。(実際には、これらの各ポインターは、へのポインターになります。これは、確かに複数のデータメンバーを持つことができるためですが、この単純な擬似コードで表すのは難しすぎます)。i
C
D
A
A