Menu
Coddy logo textTech

ネストしたクラスと内部クラス

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 38/104。

ネストされたクラスは、別のクラスの内部で定義されたクラスです。この手法は、関連する型をグループ化することでコードを整理するのに役立ち、実装の詳細を隠蔽することでカプセル化を強化できます。

class LinkedList {
public:
    class Node {    // ネストされたクラス
        int data;
        Node* next;
    public:
        Node(int d) : data(d), next(nullptr) {}
        friend class LinkedList;
    };
    
private:
    Node* head;
    
public:
    LinkedList() : head(nullptr) {}
};

ネストされたクラス NodeLinkedList と密接に結合しています。つまり、そのコンテキスト内でのみ意味を持ちます。ネストさせることで、この関係性を示し、"Node" のような汎用的な名前でグローバルな名前空間を汚染するのを避けることができます。

ネストされたクラスは、これまでに学んだのと同じアクセス規則に従います。privateセクションで宣言されたネストされたクラスは、その外部クラス内からのみアクセス可能です。

publicとして宣言されると、外部コードはスコープ演算子を使用してそれを使用できます:

LinkedList::Node node(42);    // Nodeがpublicである場合のみ

重要な詳細が1つあります:ネストされたクラスは、外部クラスのプライベートメンバに自動的にアクセスできるわけではありません。これらは、たまたま名前空間を共有しているだけの別個のクラスです。

ネストされたクラスがアクセスを必要とする場合、上記の例に示されているように、それを friend として宣言する必要があります。

challenge icon

チャレンジ

簡単

タスクがプロジェクト内で整理される、シンプルなタスク管理システムを構築しましょう。これは入れ子になったクラス(ネストされたクラス)に最適なシナリオです。TaskProjectのコンテキスト内でのみ意味を持つため、内部にネストさせることでコードを整理し、グローバル名前空間の汚染を避けることができます。

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

  • Project.h: 入れ子になった Task クラスを含む Project クラスを定義します。

    ネストされた Task クラスは、外部からアクセスできるように Projectpublic セクションで宣言する必要があります。タスク名(string)と完了ステータス(bool)を保持するようにしてください。名前を受け取り、デフォルトでタスクを未完了に設定するコンストラクタを作成します。完了としてマークする complete() メソッド、ステータスを確認する isComplete() メソッド、および名前を取得する getName() メソッドを含めてください。

    Project クラス自体は、プロジェクト名(string)と Task ポインタのコレクションを保持する必要があります。プロジェクト名を受け取るコンストラクタ、新しいタスクを作成してプロジェクトに追加する addTask(const std::string& taskName) メソッド、名前でタスクを検索して完了にする completeTask(const std::string& taskName) メソッド、およびプロジェクト名の後に各タスクのステータスを表示する displayStatus() メソッドを提供してください。

    TaskProject 内にネストされているため、Project クラスはタスクを直接操作できます。デストラクタで動的に割り当てられたタスクをクリーンアップすることを忘れないでください。

  • main.cpp: 入力からプロジェクト名と2つのタスク名(計3行)を読み取って、すべてをまとめます。指定された名前で Project を作成し、両方のタスクを追加してから、初期ステータスを表示します。最初のタスクを完了させ、ステータスを再度表示して変更を確認します。

    displayStatus() の出力形式は以下の通りです:

    Project: <project_name>
      - <task_name>: [incomplete]
      - <task_name>: [complete]

    各タスクのステータスに基づいて [complete] または [incomplete] を使用してください。

このチャレンジは、ネストされたクラスが関連する型を整理するのにどのように役立つかを示しています。Task クラスは Project と密接に結びついており、それ単体では意味をなしません。ネストさせることで、コード構造の中でこの関係を明確に示すことができます。

チートシート

ネストされたクラスは、別のクラスの内部で定義されたクラスです。関連する型をグループ化することでコードを整理し、カプセル化を強化するのに役立ちます。

class LinkedList {
public:
    class Node {    // ネストされたクラス
        int data;
        Node* next;
    public:
        Node(int d) : data(d), next(nullptr) {}
        friend class LinkedList;
    };
    
private:
    Node* head;
    
public:
    LinkedList() : head(nullptr) {}
};

ネストされたクラスは、標準的なアクセス規則に従います。privateセクションにあるネストされたクラスは、外側のクラス内からのみアクセス可能です。publicとして宣言されている場合、外部のコードからスコープ演算子を使用して利用できます:

LinkedList::Node node(42);    // Nodeがpublicである場合のみ

ネストされたクラスは、外側のクラスのprivateメンバに自動的にアクセスできるわけではありません。アクセスが必要な場合は、フレンドとして宣言します:

friend class LinkedList;

自分で試してみよう

#include <iostream>
#include <string>
#include "Project.h"

using namespace std;

int main() {
    // 入力を読み込む
    string projectName;
    string task1Name;
    string task2Name;
    
    getline(cin, projectName);
    getline(cin, task1Name);
    getline(cin, task2Name);
    
    // TODO: 指定された名前で Project を作成する
    
    // TODO: 両方のタスクをプロジェクトに追加する
    
    // TODO: 初期状態を表示する
    
    // TODO: 最初のタスクを完了させる
    
    // TODO: 変更を確認するために、再度ステータスを表示する
    
    return 0;
}
quiz icon腕試し

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

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