引数付きコンストラクタと仮想継承

zxc
記事: 79
登録日時: 13年前
住所: 日本の背骨(?)あたり

引数付きコンストラクタと仮想継承

投稿記事 by zxc » 12年前

  私はC++において、引数付きコンストラクタと仮想継承については、少なくとも内部で何をしているかの原理的な面は置いておいて、使うのにはある程度困らない程度に分かっているつもりでした。ここで2つを合わせると知らなかったものに出くわしたのでここにメモします。下の文を読むよりもリンク先を見たほうが、分かりやすいです。
  
  引数付きコンストラクタを基底クラス(以後Baseクラス)とする2クラス(以後クラスA,B)が存在するとして、その2クラスA,Bを仮想継承したクラスCがあるとする。ここでクラスCのコンストラクタは初期化リスト(?)でA,Bの引数付きコンストラクタのみを呼ぶとエラーになる。Baseの引数付きコンストラクタのみを呼んでも同様。何故か3つとも呼ばなければならないらしい。「3つとも初期化しないと駄目でしょう?」と言われるとそんな気がするが、「初期化するのは1つでは駄目なの?」と聞かれたらそれはそれで何もいえない・・・ こうなるとだけ覚えておきます。

  上手く説明するのは難しいし、拙い文章でとても説明にならないので一応参考にしたサイトのURLをはります。大変助かったリンク

YuO
記事: 947
登録日時: 14年前

Re: 引数付きコンストラクタと仮想継承

投稿記事 by YuO » 12年前

  • 引数付きのコンストラクタが存在すると,暗黙のデフォルトコンストラクタは提供されない
  • 仮想基底クラスは,最上位クラスが初期化する
  • 基底クラスの引数付きのコンストラクタを呼び出すには,明示的に呼び出す必要がある
の3つのコンボですね。
  • Base, A, Bすべてデフォルトコンストラクタが存在しない(ユーザー定義コンストラクタが存在する)ため,明示的に初期化する必要がある
  • Cは仮想基底クラスであるBaseと,直接の基底クラスであるAおよびBを初期化する必要がある
ので,Base, A, Bすべてを明示的に初期化する必要があります。

CODE:

class Base1
{
public:
//	Base1 () = delete; // 暗黙にデフォルトコンストラクタは削除される
	Base1 (int dummy) {}
};

class A1 : public virtual Base1
{
public:
//	A1 () = delete; // 暗黙にデフォルトコンストラクタは削除される
	A1 (int dummy) : Base1(dummy) {}
};

class B1 : public virtual Base1
{
public:
//	B1 () = delete; // 暗黙にデフォルトコンストラクタは削除される
	B1 (int dummy) : Base1(dummy) {}
};

class C1 : public A1, public B1
{
public:
//	C1 () = delete; // 暗黙にデフォルトコンストラクタは削除される
	C1 (int dummy) : Base1(dummy), A1(dummy), B1(dummy) {}
};

class Base2
{
public:
	Base2 () {}
	Base2 (int dummy) {}
};

class A2 : public virtual Base2
{
public:
	A2 () {} // A2 () : Base2() {} と等価
	A2 (int dummy) : Base2(dummy) {}
};

class B2 : public virtual Base2
{
public:
	B2 () {} // B2 () : Base2() {} と等価
	B2 (int dummy) : Base2(dummy) {}
};

class C2 : public A2, public B2
{
public:
	C2 () {} // C2 () : Base2(), A2(), B2() {} と等価
	C2 (int dummy) : Base2(dummy), A2(dummy), B2(dummy) {}
};

class Base3
{
public:
//	Base3 () {} // コンパイラが暗黙のうちに生成する
};

class A3 : public virtual Base3
{
public:
//	A3 () : Base3() {} // コンパイラが暗黙のうちに生成する
};

class B3 : public virtual Base3
{
public:
//	B3 () : Base3() {} // コンパイラが暗黙のうちに生成する
};

class C3 : public A3, public B3
{
public:
//	C3 () : Base3(), A3(), B3() {} // コンパイラが暗黙のうちに生成する
};

int main (void)
{
	C1 c1(1);
	C2 c2_1;
	C2 c2_2(1);
	C3 c3;

	return 0;
}

zxc
記事: 79
登録日時: 13年前
住所: 日本の背骨(?)あたり

Re: 引数付きコンストラクタと仮想継承

投稿記事 by zxc » 12年前

  分かりやすい解説・コードをありがとうございます。

  「仮想基底クラスは,最上位クラスが初期化する」 
これを知らなかったので、大分解決するまでに時間がかかってしまいました。