コンストラクタ初期化リスト
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 22/104。
以前のレッスンで、Player(std::string n, int h) : name(n), health(h) {} のようなコロン構文を見たことがあるでしょう。これはメンバイニシャライザリストと呼ばれ、C++でメンバを初期化するための推奨される方法です。
初期化子リストは、コンストラクタのパラメータリストの後にコロンで始めて記述します。各メンバはカンマで区切り、それぞれの値で直接初期化されます。
class Rectangle {
int width;
int height;
const int id;
int& reference;
public:
Rectangle(int w, int h, int i, int& r)
: width(w), height(h), id(i), reference(r) {
// コンストラクタ本体(空にすることも可能です)
}
};なぜコンストラクタ本体での代入ではなく、初期化子リストを使用するのでしょうか?代入を使用すると、メンバはまずデフォルト構築され、その後に新しい値が代入されます。初期化子リストを使用すると、メンバは正しい値で直接構築されます。これはより効率的であり、時には必須となります。
特定のメンバは、リストを使用して初期化しなければなりません:
constメンバー - コンストラクション後は代入できません
- 参照メンバ - 初期化時にバインドされる必要があります
- デフォルトコンストラクタを持たないメンバ
class Player {
const int maxHealth; // 初期化リストを使用する必要があります
std::string name;
public:
// これは動作します
Player(int max, std::string n) : maxHealth(max), name(n) {}
// これはコンパイルされません:
// Player(int max) { maxHealth = max; } // エラー!
};メンバは、初期化子リストの順序ではなく、クラス内で宣言された順序で初期化されます。混乱を避けるため、初期化子リストは常に宣言順に記述するようにしてください。
チャレンジ
簡単メンバイニシャライザリストがいつ、なぜ不可欠なのかを実証する、ゲームエンジンの設定システムを構築しましょう。イニシャライザリスト構文を使用して初期化が必須となるメンバを持つ GameConfig クラスを作成します。
コードを整理するために2つのファイルを作成します:
GameConfig.h: ゲーム設定を保存するGameConfigクラスを定義します。クラスには以下を含める必要があります:const std::string gameName— 作成後に変更できないゲームのタイトルconst int maxPlayers— コンストラクト時に固定される最大プレイヤー数int& difficultyRef— 外部の難易度設定への参照int screenWidthとint screenHeight— ディスプレイ設定用の通常のメンバ- 必要なすべてのパラメータを受け取り、すべてのメンバをイニシャライザリストを使用して初期化するコンストラクタ。イニシャライザリストは、クラスでメンバが宣言されている順序に従う必要があります。
- 設定を以下の形式で出力する
display()メソッド:Game: <gameName> Max Players: <maxPlayers> Difficulty: <difficultyRef value> Resolution: <screenWidth>x<screenHeight>
main.cpp: 入力から設定値を読み取り、GameConfig オブジェクトを作成します。以下の手順が必要です:- 入力からゲーム名 (string)、最大プレイヤー数 (int)、難易度 (int)、幅 (int)、高さ (int) を読み取ります(それぞれ別の行にあります)。
- 設定が参照する難易度用のローカル
int変数を作成します。 - イニシャライザリストコンストラクタを使用して
GameConfigオブジェクトを作成します。 display()を呼び出して初期設定を表示します。- 難易度変数を直接変更します(2倍にします)。
"After difficulty change:"と出力します。- 再度
display()を呼び出して、参照が更新された値を反映していることを示します。
このチャレンジは、なぜイニシャライザリストが重要なのかを浮き彫りにします。const メンバと参照メンバはコンストラクタの本体で代入することはできず、リスト内で初期化する必要があります。また、参照メンバは、元の変数への変更が設定オブジェクトを通じてどのように反映されるかを示しています。
main.cpp で #include "GameConfig.h" を使用してヘッダーファイルをインクルードしてください。
チートシート
メンバ初期化リストは、C++においてクラスメンバを初期化するための推奨される方法です。これはコンストラクタのパラメータリストの後にコロンで始まり、各メンバが直接初期化されます:
class Rectangle {
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {
// コンストラクタ本体
}
};なぜ初期化リストを使用するのか? メンバがデフォルト構築された後に代入されるのではなく、正しい値で直接構築されるため、より効率的になります。
特定のメンバには必須です:
constメンバ - 構築後に代入することはできません- 参照メンバ - 初期化時にバインドする必要があります
- デフォルトコンストラクタを持たないメンバ
class Player {
const int maxHealth;
int& reference;
public:
// 正解 - 初期化リストを使用
Player(int max, int& r) : maxHealth(max), reference(r) {}
// エラー - 本体でconstや参照を代入することはできません
// Player(int max) { maxHealth = max; }
};重要: メンバは初期化リストの順序ではなく、クラス内で宣言された順序で初期化されます。常に宣言順に初期化リストを記述するようにしてください。
自分で試してみよう
#include <iostream>
#include <string>
#include "GameConfig.h"
using namespace std;
int main() {
// 入力値を読み込む
string gameName;
getline(cin, gameName);
int maxPlayers;
cin >> maxPlayers;
int difficulty;
cin >> difficulty;
int width;
cin >> width;
int height;
cin >> height;
// TODO: 初期化子リストコンストラクタを使用して GameConfig オブジェクトを作成する
// コンストラクタは gameName, maxPlayers, difficulty (参照渡し), width, height を受け取る必要がある
// TODO: display() を呼び出して初期設定を表示する
// TODO: difficulty 変数を直接変更する(2倍にする)
// TODO: "After difficulty change:" と出力する
// TODO: 再度 display() を呼び出して更新された設定を表示する
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス