2

C# では、継承をまたいでコンストラクターをチェーンすることは便利で便利です。C++ で同様の機能を実装する最良の方法は何ですか? これが私が表現したいことです:

struct A
{
    A(int p)
    {
        i = p;
    }

    int i;
};

struct B : virtual A
{
    B(int q) : A(q)
    {
    }
};

struct C : virtual B
{
    C(int r) : B(r) // call B::B() which in turn would call A::A()
    {
    }
};

何か案は?

乾杯、チャーリー。

4

2 に答える 2

3

最も派生したクラス (つまりC) は、すべての仮想基本クラスの構築を担当します。したがって、とCの両方Aを初期化できBます。

C(int r) : A(r), B(r)

仮想基底クラスは、非仮想基底クラスの前に初期化されることに注意してください。B仮想基本クラスを初期化する方法はありませんA

Aたとえば、仮想ベースのデフォルトを構築可能にしてから、コンストラクターで呼び出すことができる「初期化」メソッドを与えることで、何かを一緒にハックできますが、Bそうすると危険であることが判明する可能性があります。B基本クラスのサブオブジェクトに対してコンストラクターが呼び出された場合、仮想的に派生するBの他の基本クラスが既に初期化されている (そして潜在的に既に使用されている) かどうか、またはコンストラクターが実行しようとしている唯一のクラスであるかどうかを知る方法はありません。初期化を試みます。CAAA

于 2012-08-13T18:23:16.757 に答える
2

C++ では、仮想継承では、すべての仮想ベースのコンストラクターを明示的に呼び出すために、最も派生した型のコンストラクターが必要です。

C( int r ) : A(r), B(r) {}

仮想継承が必要であると明確に述べていますが、仮想継承を使用することは一般的ではないため、ユース ケースを説明することをお勧めします。これを必要とせず、コンストラクターの連鎖を許可する代替手段があるかもしれません。


最も派生した型がコンストラクターを呼び出す必要があることに疑問を持っている場合、その理由は、virtual継承が完全なオブジェクトにそのようなベースが 1 つしかないことを意味するためです。考えられる関係を考えると:

struct base { base( int x ); /*...*/ };
struct d1 : virtual base {
   d1() : base(1) {}
// ...
};
struct d2 : virtual base {
   d2() : base(2) {}
// ...
};
struct final : d1, d2 {};

baseinsideの単一インスタンスのコンストラクターに渡す値はfinal? 2 つの異なる継承パスが競合する値を渡していますが、初期化するオブジェクトは 1 つです。異なる呼び出しが競合していなくても、別のコンパイル モデルを使用すると、コンパイラはそれを認識できないため、唯一のオプションは、完全なオブジェクトが仮想ベースを初期化する方法を決定することです。

于 2012-08-13T18:24:12.093 に答える