仮想継承は「ダイヤモンド」(多重継承)の曖昧さをどのように解決するのでしょうか? 質問する

仮想継承は「ダイヤモンド」(多重継承)の曖昧さをどのように解決するのでしょうか? 質問する
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

この型にはD2 つの vtable ポインター (最初の図で確認できます) があり、1 つは 用B、もう 1 つはCを仮想的に継承しますADのオブジェクト サイズは、現在 2 つのポインターを格納するため増加しますが、現在は 1 つしかありませんA

したがってB::A、 と はC::A同じであり、 からのあいまいな呼び出しは発生しませんD。仮想継承を使用しない場合は、上記の 2 番目の図のようになります。A のメンバーへの呼び出しはすべてあいまいになり、どのパスを取るかを指定する必要があります。

Wikipediaには別の良い概要と例がここにあります

おすすめ記事