13_コンストラクタのオーバーロードと初期化リスト

はじめに

この章では、C++でクラスをさらに柔軟に使うための次の2つを学びます。

コンストラクタのオーバーロードとは

オーバーロードとは「同じ名前で複数のバリエーション」を定義することです。

C++では同じ名前引数の数や型が異なるものを複数定義でき、呼び出し時に与える引数の形に応じて適切な関数が選ばれる、という仕組みがオーバーロードです。

コンストラクタをオーバーロードすることで、

例:オーバーロードされたコンストラクタ

#include <iostream>
using namespace std;

class Player {
private:
    string name;

public:
    Player() {
        name = "Unknown";
    }

    Player(string n) {
        name = n;
    }

    void greet() {
        cout << "こんにちは、" << name << " さん!" << endl;
    }
};

int main() {
    Player p1;           // 名前指定なし
    Player p2("Yamada");  // 名前指定あり

    p1.greet();
    p2.greet();

    return 0;
}

解説

初期化リスト

初期化リストは、コンストラクタの処理の前に直接変数を初期化するための仕組みです。

class Player {
private:
    string name;

public:
    Player(string n) : name(n) {
        // 初期化リストで name に n をセット
    }
};

初期化リストのメリット

初期化リストの実例

#include <iostream>
using namespace std;

class Product {
private:
    string name;
    int price;

public:
    Product(string n, int p) : name(n), price(p) {
        // ここで特に何もしなくても、上で初期化済み
    }

    void show() {
        cout << name << " は " << price << " 円です。" << endl;
    }
};

int main() {
    Product apple("りんご", 150);
    apple.show();

    return 0;
}

理解度チェック

問題13-1

次のコードを実行すると何が表示されますか?

#include <iostream>
using namespace std;

class Hero {
private:
    string name;

public:
    Hero() : name("Unknown") {}
    Hero(string n) : name(n) {}

    void show() {
        cout << name << " が現れた!" << endl;
    }
};

int main() {
    Hero h1;
    Hero h2("Link");

    h1.show();
    h2.show();

    return 0;
}
解説を表示 正解:ウ
h1 は引数なしで生成されるので Hero() が呼ばれ name は "Unknown"。h2("Link") は引数ありなので Hero(string n) が呼ばれ name は "Link"。結果、上から "Unknown が現れた!" → "Link が現れた!" の順で出力されます。

問題13-2

初期化リストを使ったコンストラクタの説明として正しいものはどれですか?

解説を表示 正解:イ
初期化リストはコンストラクタ本体 { } が実行される前に、メンバ変数を直接初期化します。private・publicどちらのメンバにも使用でき、constメンバや参照メンバの初期化に必須です。

問題13-3

次のコードはコンパイルできますか?

class Box {
private:
    const int size;
public:
    Box(int s) {
        size = s;  // コンストラクタ本体で代入
    }
};
解説を表示 正解:ウ
const メンバはオブジェクト生成後に変更できません。コンストラクタ本体 { } に到達した時点ですでに初期化済みでなければならないため、size = s; はエラーになります。正しくは Box(int s) : size(s) {} と初期化リストを使います。

問題13-4

次のコードを実行したとき、出力はどれになりますか?

#include <iostream>
using namespace std;

class Counter {
private:
    int count;
public:
    Counter() : count(0) {}
    Counter(int n) : count(n) {}
    void show() { cout << count << endl; }
};

int main() {
    Counter c1;
    Counter c2(5);
    c1.show();
    c2.show();
    return 0;
}
解説を表示 正解:ア
c1 は引数なしで Counter() が呼ばれ count は 0。c2(5)Counter(int n) が呼ばれ count は 5。よって出力は 0 → 5 の順になります。

コーディング演習

演習1:基本コードを動かす

13_01_ctor_overload.cpp を作成し、次のコードを入力して実行しましょう。
// main.cpp
#include <iostream>
using namespace std;

class Player {
private:
    string name;

public:
    Player() : name("Unknown") {}
    Player(string n) : name(n) {}

    void greet() {
        cout << "こんにちは、" << name << " さん!" << endl;
    }
};

int main() {
    Player p1;
    Player p2("Yamada");

    p1.greet();
    p2.greet();

    return 0;
}

演習2:コードを改造する

13_01_CtorOverloadmain.cpp をコピーして 13_02_CtorMod に貼り付け、次の変更を加えてみましょう:

まとめ