コンストラクタ 解答ページ | Programming Place Plus 新C++編

トップページ新C++編コンストラクタ

このページの概要

このページは、練習問題の解答例や解説のページです。



解答・解説

問題1 (確認★)

次のように定義されたクラスがあります。

class C {
public:
    C(int a)
    {}

    C(int a1, int a2)
    {}
};

このとき、以下のそれぞれの変数定義はどのような結果になりますか?

C c1;
C c2(100);
C c3(10, 20);


クラスC には、ユーザー定義のコンストラクタ(本編解説)が2つ定義されています。同じ名前の関数(ここでは C という名前のコンストラクタ)を、同じスコープ(ここではクラスC のクラススコープ)で定義しているので、これはオーバーロード(本編解説)をしていることになります。ユーザー定義のコンストラクタがあるので、コンパイラによるコンストラクタの自動生成は行われません(本編解説)。

c1 の定義には初期化子がありません。クラス型の変数を定義するときに初期化子が省略されているときには、デフォルトコンストラクタを使用します(本編解説)。デフォルトコンストラクタとは、実引数の指定なしで呼び出せるコンストラクタのことですが、クラスC にはそのようなコンストラクタは存在しないので、コンパイルエラーになります。

c2(100) を与えています。int型の値を1つ渡しているので、C(int a) のコンストラクタと一番良く一致しており、これが呼び出されます。

c3(10, 20) を与えています。int型の値を2つ渡しているので、C(int a1, int a2) のコンストラクタと一番良く一致しており、これが呼び出されます。

問題2 (確認★)

問題1と同じ要領で、次の場合はどのような結果になりますか?

class C {
public:
    C() = default;

    C(int a)
    {}

    C(int a1, int a2)
    {}
};

C c1;
C c2(100);
C c3(10, 20);
C c4 {};
C c5 {100};
C c6 {10, 20};


クラス定義に C() = default; が加わりました。これは、コンパイラが暗黙的に生成するコンストラクタを、明示的に定義する記述で、明示的にデフォルト化されたコンストラクタが定義されます(本編解説)。

その結果として、問題1と違って、デフォルトコンストラクタが存在するようになりました。そのため、c1 の定義が成功するようになります。

c2c3 の結果には違いは起こりません。それぞれ適切なコンストラクタが呼び出されます。

c4c5c6 はリスト初期化の構文を使っています。この場合、仮引数が std::initializer_list であるコンストラクタを優先して使おうとしますが、存在しなければ、{}() であるとみなして対応しようとします(本編解説)。そのため、c4 は実引数なしで呼び出せるデフォルトコンストラクタが使用され、c5 は int型が1つのコンストラクタを、c6 は int型が2つのコンストラクタを使用します。

問題3 (確認★)

問題1~2と同じ要領で、次の場合はどのような結果になりますか?

class C {
public:
    C(int a = 0)
    {}

    C(int a1, int a2, int a3 = 1000)
    {}
};

C c1;
C c2(100);
C c3(10, 20);
C c4 {};
C c5 {100};
C c6 {10, 20};
C c7 {10, 20, 30};


= default によって明示的にデフォルト化されたコンストラクタを削除し、残りのコンストラクタにデフォルト実引数を追加しました(本編解説)。実引数を指定されなかった場合に、仮引数のところに記述されているデフォルトの値が使用されるようになります。

明示的にデフォルト化されたコンストラクタが消えると、デフォルトコンストラクタがなくなりそうですが、C(int a = 0) があるので、実引数を指定しない呼び出しが可能であり、こちらがデフォルトコンストラクタとして機能します。よって、c1c4 は依然としてデフォルトコンストラクタを呼び出します。

c2 は int型の実引数が1つなので、C(int a = 0) を使用します。デフォルトの値は無視され、指定どおり 100 が渡されます。

c3 は int型の実引数が2つなので、C(int a1, int a2, int a3 = 1000) を使用します。3つ目の実引数が指定されていませんが、デフォルト実引数になっているので 1000 を指定したことになります。

c5c6 も同じ理由で、C(int a = 0)C(int a1, int a2, int a3 = 1000) が使用されます。

c7 は実引数が3つあるので、C(int a1, int a2, int a3 = 1000) が使用されます。3つ目の実引数は、デフォルトの値は無視され、指定どおり 30 が渡されます。

問題4 (確認★)

問題1~3と同じ要領で、次の場合はどのような結果になりますか?

class C {
public:
    C(int a = 0)
    {}

    C(int a1, int a2, int a3 = 1000)
    {}

    C(std::initializer_list<int> lst)
    {}
};

C c1;
C c2(100);
C c3(10, 20);
C c4 {};
C c5 {100};
C c6 {10, 20};
C c7 {10, 20, 30};


クラス定義に、仮引数が std::initializer_list<int> のコンストラクタが追加されました。これは初期化リストコンストラクタと呼ばれます。初期化子リストコンストラクタは、空でない {} を使ったリスト初期化の構文で初期化されるときに優先的に使用されます(本編解説)。

c1c2c3{} を使っていないので、結果に影響はありません。

c4 は中身が空の {} を与えています。中身が空の場合は特別扱いされ、デフォルトコンストラクタがあるのならそれを呼び出します(なければ、初期化子リストコンストラクタを呼ぶ)。したがって、C(int a = 0) のコンストラクタが使用されます。

c5{100} を与えています。C(int a = 0) のコンストラクタと一致するようにもみえますが、{} を使っているため、初期化子リストコンストラクタのほうが使用されます。もし、初期化子リストコンストラクタがなければ、{}() とみなすルールによって、C(int a = 0) のほうが使用されることになります。

c6{10, 20} を与えています。C(int a1, int a2, int a3 = 1000) のコンストラクタと一致するようにもみえますが、{} を使っているため、初期化子リストコンストラクタのほうが使用されます。もし、初期化子リストコンストラクタがなければ、{}() とみなすルールによって、C(int a1, int a2, int a3 = 1000) のほうが使用されることになります。

c7{10, 20, 30} を与えています。初期化子リストコンストラクタが使用されます。


参考リンク



更新履歴




はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る