ネストしたクラスと内部クラス
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) {}
};ネストされたクラス Node は LinkedList と密接に結合しています。つまり、そのコンテキスト内でのみ意味を持ちます。ネストさせることで、この関係性を示し、"Node" のような汎用的な名前でグローバルな名前空間を汚染するのを避けることができます。
ネストされたクラスは、これまでに学んだのと同じアクセス規則に従います。privateセクションで宣言されたネストされたクラスは、その外部クラス内からのみアクセス可能です。
publicとして宣言されると、外部コードはスコープ演算子を使用してそれを使用できます:
LinkedList::Node node(42); // Nodeがpublicである場合のみ重要な詳細が1つあります:ネストされたクラスは、外部クラスのプライベートメンバに自動的にアクセスできるわけではありません。これらは、たまたま名前空間を共有しているだけの別個のクラスです。
ネストされたクラスがアクセスを必要とする場合、上記の例に示されているように、それを friend として宣言する必要があります。
チャレンジ
簡単タスクがプロジェクト内で整理される、シンプルなタスク管理システムを構築しましょう。これは入れ子になったクラス(ネストされたクラス)に最適なシナリオです。TaskはProjectのコンテキスト内でのみ意味を持つため、内部にネストさせることでコードを整理し、グローバル名前空間の汚染を避けることができます。
コードを整理するために2つのファイルを作成します:
Project.h: 入れ子になったTaskクラスを含むProjectクラスを定義します。ネストされた
Taskクラスは、外部からアクセスできるようにProjectの public セクションで宣言する必要があります。タスク名(string)と完了ステータス(bool)を保持するようにしてください。名前を受け取り、デフォルトでタスクを未完了に設定するコンストラクタを作成します。完了としてマークするcomplete()メソッド、ステータスを確認するisComplete()メソッド、および名前を取得するgetName()メソッドを含めてください。Projectクラス自体は、プロジェクト名(string)とTaskポインタのコレクションを保持する必要があります。プロジェクト名を受け取るコンストラクタ、新しいタスクを作成してプロジェクトに追加するaddTask(const std::string& taskName)メソッド、名前でタスクを検索して完了にするcompleteTask(const std::string& taskName)メソッド、およびプロジェクト名の後に各タスクのステータスを表示するdisplayStatus()メソッドを提供してください。TaskはProject内にネストされているため、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;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタ引数付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ詳解Rule of Three / Five / Zeroまとめ - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () 演算子のオーバーロード型変換演算子まとめ:Matrix クラス