4

C++ のサンプル コード:

class A {
  public:
    A(int) {}
};

class B : public virtual A {
  public:
    B(int b) : A(b) {}
};

class C : virtual public A {
  public:
    C(int c) : A(c) {}
};

class D : public B, public C {
  public:
    D() : B(1), C(2){};
};

これは、ダイヤモンド問題の典型的なコード (ソリューション) です。virtual キーワードが使用される理由を認識しています。しかし、コンパイラが問題を処理する内部メカニズムは私にはわかりません。今、私は、以下に述べるように、上記のメカニズムについて2つの異なる理論に出くわしました.

  1. クラスが virtual キーワードで継承されると、コンパイラは派生クラスに仮想ベース ポインターを追加します。派生クラスのサイズを確認しましたが、追加のポインターのサイズが含まれています。しかし、上記の例でクラス A のメンバーがクラス D で参照されている場合、それがどこを指しているのか、どのように機能するのかはわかりません。

  2. コンストラクターごとに、コンパイラーは、プログラマーによって提供された各定義の 2 つのバージョンを作成します。 上記のコードなどで、このリンクから知りました。コンパイラは C のコンストラクタの 2 つのバージョンを生成します

     C(int){}           // Version1
    
     C(int):A(int){}    // Version2 
    

    そして、コンストラクター B の 2 つの異なるバージョン

     B(int){}           // Version1
    
     B(int):A(int){}    // Version2
    

    したがって、D が構築されると、コンパイラは以下のコードのいずれかを生成します。

    D() : B(), C(2) {}  // Version1
    
    D() : B(1), C() {}  // Version2
    

    A のインスタンスが 1 つだけ作成されるようにするため、A の重複コピーが回避されます。

内部メカニズムを理解するのを手伝ってください。

4

1 に答える 1