1

次のコードでは、C のオブジェクトを作成すると、A のデフォルト コンストラクターが B のコンストラクターを介して呼び出されます。なぜそうなるのでしょうか?

#include <iostream>
using namespace std;

class A
{
public:
    int a;
    A(int z): a(z) {cout<<"a is "<<a;}
    A() { cout<<" it came here\n";}
};

class B: public virtual A
{
public:
    B(int z): A(z) {cout<<"in B and z is "<<z<<"\n"; }
};

class C:public B
{
public:
    C(int z): B(z) {cout<<" In C\n"; }
};

int main()
{
    C b(6);
    cout<<b.a;
    return 0;
}
4

1 に答える 1

0

これが、仮想継承が標準で記述されている方法です。

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

特に、 を構築するC場合、Aサブオブジェクトは他の何よりも先に初期化されます (Bサブオブジェクトを含む)。は問題のあるコンストラクターのリストにAないため、デフォルトのコンストラクターが使用されます。mem-initializersCA

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

次に、Bサブオブジェクトが構築されます。

[12.6.2] mem -initializer-idが仮想基本クラスを示す mem-initializer は、最も派生したクラスではないクラスのコンストラクターの実行中に無視されます。

: A(z)のコンストラクター内のは、 のサブオブジェクトをB構築するときに無視されます。BC

日常的な言語では、これは、直接または間接の派生クラスごとに、直接の派生クラスであるかのように、仮想基本クラスを初期化する必要があることを意味します。これを忘れると、デフォルトのコンストラクターが強制され、壊滅的な結果を招く可能性があります。(そのため、任意の仮想基本クラスで既定のコンストラクターのみを使用するか、既定のコンストラクターをまったく使用しないようにする必要があります)。

于 2013-09-25T07:49:29.270 に答える