通常の (仮想) コンストラクターの呼び出し順序をバイパスする (実用的な) 方法はありますか?
例:
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 がそれを呼び出さなければならないのはなぜですか?