11

通常の (仮想) コンストラクターの呼び出し順序をバイパスする (実用的な) 方法はありますか?

例:

class A
{
    const int i;

public:
    A()
      : i(0)
    { cout << "calling A()" << endl; }

    A(int p)
      : i(p)
    { cout << "calling A(int)" << endl; }
};

class B
    : public virtual A
{
public:
    B(int i)
      : A(i)
    { cout << "calling B(int)" << endl; }
};

class C
    : public B
{
public:
    C(int i)
      : A(i), B(i)
    { cout << "calling C(int)" << endl; }
};

class D
    : public C
{
public:
    D(int i)
      : /*A(i), */ C(i)
    { cout << "calling D(int)" << endl; }
};


int main()
{
    D d(42);
    return 0;
}

出力:

A( int) の
呼び出し B(int)の
呼び出し C(int)の
呼び出し D(int ) の呼び出し

私がしたいのは次のようなものです:

A(int) の
呼び出し B(int)の
呼び出し C(int)の
呼び出し D(int ) の呼び出し


ご覧のとおり、仮想継承が関係しているため、D のコンストラクターは最初に A のコンストラクターを呼び出しますが、パラメーターが指定されていないため、A() を呼び出します。初期化が必要なconst int i があるので、問題があります。

私がやりたいのは、C の継承の詳細を非表示にすることです。そのため、D (およびすべての派生) コンストラクターの初期化リストで A(i) を呼び出さないようにする方法を探しています。[編集] この特定のケースでは、C の非仮想単一継承の子クラスしかないと仮定できます (D は 1 つなので)。[/編集]

[編集]

仮想基本クラスは、非仮想基本クラスが初期化される前に初期化されるため、最も派生したクラスのみが仮想基本クラスを初期化できます。– ジェームズ・マクネリス

それがまさにポイントです。最も派生したクラスが仮想基本クラスのコンストラクターを呼び出す ことは望ましくありません。[/編集]

次の状況を考えてみましょう (上記のコード例には示されていません)。

  A
 / \
B0  B1
 \ /
  C
  |
  D  

C をインスタンス化するときに C が A の ctor を呼び出さなければならない理由 (あいまいさ) は理解できますが、D をインスタンス化するときに D がそれを呼び出さなければならないのはなぜですか?

4

4 に答える 4

7

残念ながら、常に最も派生したクラスから仮想基本クラスのコンストラクターを呼び出す必要があります。

これは、仮想ベースが、オブジェクトのインスタンスの仮想ベースから派生するすべてのクラス間で共有されていると言っているためです。オブジェクトの特定のインスタンスに対してコンストラクターを呼び出すことができるのは1回だけなので、コンパイラーは仮想ベースを共有するクラスの数を知らないため、最も派生したクラスのコンストラクターを明示的に呼び出す必要があります( C ++プログラミング言語第3版、セクション15.2.4.1)。これは、コンパイラーが最も基本的なクラスのコンストラクターから開始し、最も派生したクラスで動作するためです。仮想基本クラスから直接継承するクラスは、標準では仮想基本クラスコンストラクターを呼び出さないため、明示的に呼び出す必要があります。

于 2010-08-16T17:12:28.673 に答える
2

Cをインスタンス化するときにCがAのコンストラクター(あいまいさ)を呼び出さなければならない理由は理解できますが、Dをインスタンス化するときにDがそれを呼び出さなければならないのはなぜですか?

Cがそれを呼び出さなければならないのと同じ理由で。これはあいまいさの問題ではありません。Aの構成要素は1回だけ呼び出す必要があるという事実です(仮想ベースであるため)。

CがAのコンストラクターを初期化できることを期待している場合、クラスDがCと、最終的にAを継承する別のクラスを継承するとしたらどうでしょうか。

于 2010-08-16T17:11:33.413 に答える
-1

parashift c++-faq-lite では、この問題は概説されています。

于 2010-08-16T17:05:00.753 に答える