委譲コンストラクタ
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 23/104。
共通の初期化ロジックを共有する複数のコンストラクタがある場合、コードの重複を避けるために委譲コンストラクタ (delegating constructors)を使用できます。委譲コンストラクタは、その初期化子リストの中で同じクラスの別のコンストラクタを呼び出します。
class Player {
std::string name;
int health;
int level;
public:
// 基本コンストラクタ - 実際の処理を行います
Player(std::string n, int h, int lvl)
: name(n), health(h), level(lvl) {}
// 基本コンストラクタに委譲します
Player(std::string n) : Player(n, 100, 1) {}
// デフォルトコンストラクタも委譲します
Player() : Player("Unknown") {}
};委譲は、クラス名の後に引数を記述して初期化リスト内で行われます。Player() が呼び出されると、Player(std::string) に委譲され、そこからさらに3つの引数を持つコンストラクタへと委譲されます。この連鎖は、ターゲットとなるコンストラクタから元のコンストラクタへと順に実行されます。
重要なルールが1つあります。委譲コンストラクタは、初期化リストに他のメンバを持つことはできません。委譲が唯一の項目である必要があります。
class Item {
int id;
int value;
public:
Item(int i, int v) : id(i), value(v) {}
// エラー!委譲とメンバ初期化を混在させることはできません
// Item(int i) : Item(i, 0), id(i) {}
// 正解 - 委譲のみ
Item(int i) : Item(i, 0) {}
};委譲コンストラクタは、初期化ロジックを1か所に集約するのに役立ち、コードのメンテナンスを容易にし、コードの重複によるエラーを減らすことができます。
チャレンジ
簡単コンストラクタの委譲(delegating constructors)を使用して、コンストラクタ呼び出しを連鎖させることでコードの重複を排除する方法を示す、接続設定システムを構築しましょう。
コードを整理するために2つのファイルを作成します:
Connection.h: さまざまな設定オプションを持つネットワーク接続を表すConnectionクラスを定義します。クラスには以下を含める必要があります:- プライベートメンバ:
host(string)、port(int)、timeout(秒単位の int)、およびsecure(bool) - 4つすべてのパラメータを受け取り、初期化リストを使用してすべてのメンバを初期化する主要コンストラクタ。このコンストラクタは
"Connection configured: <host>:<port>"と出力する必要があります。 hostとportのみを受け取り、timeoutのデフォルト値を30、secureのデフォルト値をfalseとして主要コンストラクタに委譲するコンストラクタ。hostのみを受け取り、portのデフォルト値を80として2引数コンストラクタに委譲するコンストラクタ。hostのデフォルト値を"localhost"として1引数コンストラクタに委譲するデフォルトコンストラクタ。"<host>:<port> (timeout: <timeout>s, secure: <yes/no>)"という形式の文字列を返すgetInfo()メソッド。
- プライベートメンバ:
main.cpp: 異なるコンストラクタを使用して接続を作成し、委譲の連鎖を実演します。入力からホスト名とポート番号を(それぞれ別の行で)読み取り、以下の操作を行います:- デフォルトコンストラクタを使用して
Connectionを作成する - 入力されたホストのみを使用して
Connectionを作成する - 入力されたホストとポートの両方を使用して
Connectionを作成する - 入力されたホスト、入力されたポート、タイムアウト
60、セキュア設定をtrueにしてConnectionを作成する - 各接続の
getInfo()を1行に1つずつ出力する
- デフォルトコンストラクタを使用して
委譲の連鎖は次のように流れます:デフォルトコンストラクタが1引数コンストラクタを呼び出し、それが2引数コンストラクタを呼び出し、それが主要な4引数コンストラクタを呼び出します。これにより、オブジェクトが作成されるたびに、常に主要コンストラクタから "Connection configured" メッセージが1回出力されます。
getInfo() 内のセキュアステータスについては、secureがtrueの場合は "yes" を、そうでない場合は "no" を出力してください。
main.cpp で #include "Connection.h" を使用してヘッダーファイルをインクルードしてください。
チートシート
委譲コンストラクタ(delegating constructor)は、コードの重複を避けるために、初期化リスト内で同じクラスの別のコンストラクタを呼び出します。
class Player {
std::string name;
int health;
int level;
public:
// 基本コンストラクタ
Player(std::string n, int h, int lvl)
: name(n), health(h), level(lvl) {}
// 基本コンストラクタに委譲
Player(std::string n) : Player(n, 100, 1) {}
// デフォルトコンストラクタも委譲する
Player() : Player("Unknown") {}
};委譲は、クラス名の後に引数を続ける形で初期化リスト内で行われます。コンストラクタは、あるコンストラクタが別のコンストラクタに委譲するという、委譲の連鎖を形成することができます。
重要なルール: 委譲コンストラクタは、初期化リストに他のメンバを持つことはできません。委譲が唯一の項目である必要があります。
class Item {
int id;
int value;
public:
Item(int i, int v) : id(i), value(v) {}
// エラー!委譲とメンバ初期化を混在させることはできません
// Item(int i) : Item(i, 0), id(i) {}
// 正解 - 委譲のみ
Item(int i) : Item(i, 0) {}
};自分で試してみよう
#include <iostream>
#include <string>
#include "Connection.h"
using namespace std;
int main() {
// 入力を読み込む
string host;
int port;
cin >> host;
cin >> port;
// TODO: デフォルトコンストラクタを使用して Connection を作成する
// TODO: 入力された host のみを使用して Connection を作成する
// TODO: 入力された host と port の両方を使用して Connection を作成する
// TODO: 入力された host、port、および timeout=60, secure=true を指定して Connection を作成する
// TODO: 各接続に対して getInfo() を1行に1つずつ出力する
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス