class A { public: void eat(){ cout<<"A";} };
class B: virtual public A { public: void eat(){ cout<<"B";} };
class C: virtual public A { public: void eat(){ cout<<"C";} };
class D: public B,C { public: void eat(){ cout<<"D";} };
int main(){
A *a = new D();
a->eat();
}
ダイヤモンドの問題は理解していますが、上記のコードにはその問題はありません。
仮想継承は具体的にどのように問題を解決するのでしょうか?
私が理解していること:と言う場合A *a = new D();
、コンパイラは 型のオブジェクトをD
型のポインターに割り当てることができるかどうかを知りたいのですA
が、従うことができるパスが 2 つありますが、それ自体では決定できません。
では、仮想継承はどのようにして問題を解決するのでしょうか (コンパイラが決定を下すのを支援する)?
ベストアンサー1
あなたが望むこと:(仮想継承で実現可能)
A
/ \
B C
\ /
D
そしてそうではありません:(仮想継承がない場合に何が起こるか)
A A
| |
B C
\ /
D
仮想継承とは、基本クラスのインスタンスが 2 つではなく 1 つだけ存在することを意味しますA
。
この型にはD
2 つの vtable ポインター (最初の図で確認できます) があり、1 つは 用B
、もう 1 つはC
を仮想的に継承しますA
。D
のオブジェクト サイズは、現在 2 つのポインターを格納するため増加しますが、現在は 1 つしかありませんA
。
したがってB::A
、 と はC::A
同じであり、 からのあいまいな呼び出しは発生しませんD
。仮想継承を使用しない場合は、上記の 2 番目の図のようになります。A のメンバーへの呼び出しはすべてあいまいになり、どのパスを取るかを指定する必要があります。