1

仮想継承を使用してこのプログラムを作成しましたが、いくつか質問があります。

#include<iostream>
using namespace std;

class B1
{
 public:
  B1()
  {
    cout << "In B1 constructor\n";
  }
};

class V1 : public B1
{
 public:
  V1()
  {
    cout << "In V1 constructor\n";
  }
};

class D1 : virtual public V1
{
 public:
  D1()
  {
    cout << "In D1 constructor\n";
  }
};

class B2
{
 public:
  B2()
  {
    cout << "In B2 constructor\n";
  }
};

class B3 {
 public:
  B3()
  {
    cout << "In B3 constructor\n";
  }
};

class V2 : public B1, public B2
{
 public:
  V2()
  {
    cout << "In V2 constructor\n";
  }
};

class D2 : public B3, virtual public V2
{
 public:
  D2()
  {
    cout << "In D2 constructor\n";
  }
};

class X : public D1, virtual public D2
{
 public:
  X()
  {
    cout << "In X constructor\n";
  }
};

int main()
{
  X x;
  return 0;
}

プログラムの出力:

In B1 constructor
In V1 constructor
In B1 constructor
In B2 constructor
In V2 constructor
In B3 constructor
In D2 constructor
In D1 constructor
In X constructor

次のような出力が期待されていました。

In B1 constructor
In B2 constructor
In V2 constructor
In B2 constructor
In D2 constructor
In B1 constructor
In V1 constructor
In D1 constructor
In X constructor

仮想基本クラスのオブジェクトが最初に構築され、次に他の基本クラスオブジェクトが構築されることに基づいています。誰かがこの動作を説明できますか?

4

2 に答える 2

3

標準からの正確な引用は 12.6.2p10 です。

非委任コンストラクターでは、初期化は次の順序で進行します。

— 最初に、最も派生したクラス (1.8) のコンストラクターに対してのみ、仮想基底クラスは、基底クラスの有向非巡回グラフの深さ優先の左から右への走査に現れる順序で初期化されます。 -to-right」は、派生クラス base-specifier-list 内の基底クラスの出現順序です。

— 次に、直接基底クラスは、base-specifier-list に表示される宣言順に初期化されます (mem-initializer の順序に関係なく)。

— 次に、非静的データ メンバーは、クラス定義で宣言された順序で初期化されます (これも mem-initializer の順序に関係なく)。

— 最後に、コンストラクター本体の複合ステートメントが実行されます。

重要なのは、太字のテキストの左から右への深さ優先だと思います。クラスはのV1仮想ベースであり、階層がより深い場合でもX、 の左側にあります。V2

あなたの場合の階層グラフは次のようになります。

            X
          /   \\
        D1     D2
        ||    / \\
        V1  B3   V2
        |       /  \
        B1    B1*   B2

一重線は単純な継承を識別し、二重線は仮想継承を表します。B1完全なオブジェクトには の 2 つのインスタンスがあることに注意してくださいX。ここで、深さ優先の左から右への検索を実行すると、次の順序でノードをたどることになります。

[ B1, V1, D1, B3, B1*, B2, V2, D2, X ]

仮想ベースはV1V2D2であり、構築される順序です。V1の構築が必要ですB1V2と の構築が必要でB1*ありB2D2が必要なB3ので、順序は次のようになります。

[ B1, V1, B1*, B2, V2, B3, D2, D1, X ]

B1によって構築がトリガーされV1B1*の前にB2順序付けする必要がある場合は、 の依存関係としてトリガーされます。この時点で、すべての仮想ベースが構築され、非仮想ベースの構築が開始されます。仮想ベースの依存関係のために初期化されていない唯一の非仮想ベースは です。V2B3D2XD1

ひし形が閉じていて (たとえば、から実質的V1に継承されている場合)、のインスタンスは 1 つしかなく、それが構築される最初のサブオブジェクトになります。V2B1B1

于 2012-04-24T19:14:42.140 に答える
0

C++ は常に「最初の」または「最も基本的な」クラスを最初に構築します。次に、継承ツリーを順番にたどり、連続する各派生クラスを構築します。

于 2012-04-24T19:09:06.207 に答える