1. ホーム
  2. c++

[解決済み] 仮想継承は "ダイヤモンド"(多重継承)の曖昧さをどのように解決するか?

2022-11-04 22:03:35

質問

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つの経路を持ちますが、それ自身で決定することはできません。

では、仮想継承はどのように問題を解決するのでしょうか(コンパイラが決定を下すのを助ける)?

どのように解決するのか?

あなたがしたい。 (仮想継承で実現可能)

  A  
 / \  
B   C  
 \ /  
  D 

とはならない。 (仮想継承を行わない場合)

A   A  
|   |
B   C  
 \ /  
  D 

仮想継承とは、ベースとなる A クラスのインスタンスが2つではなく、1つだけ存在することを意味します。

あなたのタイプ D は2つのvtableポインタを持ち(最初の図にあります)、1つは B に対するものと C を事実上継承している人 A . D のオブジェクトサイズは、2 つのポインタを保存しているため大きくなっています。 A は一つしかありません。

そこで B::AC::A は同じものであり、そのため D . 仮想継承を使用しない場合、上の2番目の図のようになります。 そして、Aのメンバへの呼び出しは曖昧になり、どちらのパスを取りたいかを指定する必要があります。

Wikipediaに詳しい説明と例があります。