Menu
Coddy logo textTech

委譲コンストラクタ

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か所に集約するのに役立ち、コードのメンテナンスを容易にし、コードの重複によるエラーを減らすことができます。

challenge icon

チャレンジ

簡単

コンストラクタの委譲(delegating constructors)を使用して、コンストラクタ呼び出しを連鎖させることでコードの重複を排除する方法を示す、接続設定システムを構築しましょう。

コードを整理するために2つのファイルを作成します:

  • Connection.h: さまざまな設定オプションを持つネットワーク接続を表す Connection クラスを定義します。クラスには以下を含める必要があります:
    • プライベートメンバ: host (string)、port (int)、timeout (秒単位の int)、および secure (bool)
    • 4つすべてのパラメータを受け取り、初期化リストを使用してすべてのメンバを初期化する主要コンストラクタ。このコンストラクタは "Connection configured: <host>:<port>" と出力する必要があります。
    • hostport のみを受け取り、timeout のデフォルト値を 30secure のデフォルト値を 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;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン