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」のような汎用的な名前でグローバル名前空間を汚染することを避けられます。

Nested クラスは、これまで学んだものと同じアクセス規則に従います。private セクションで宣言された Nested クラスには、外側のクラス内からのみアクセスできます。

public として宣言されている場合、外部コードはスコープ演算子を使って利用できます。

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

方向に関する重要な点が1つあります。nested classは、それを囲むclassのメンバーであり、他のメンバーと同じアクセス権を持つため、friend宣言なしで、それを囲むclassのprivateメンバーにアクセスできます。ただし、その逆は自動的には行われません。つまり、それを囲むclassから、nested classのprivateメンバーにアクセスすることはできません。

そのため、上の例では Nodefriend class LinkedList; を宣言しています。friend 宣言によって、外側の LinkedListNode の private メンバーにアクセスできるようになります。これは自動では行われない唯一の方向です。

challenge icon

チャレンジ

簡単

タスクをプロジェクト内で整理する、シンプルなタスク管理システムを構築しましょう。これはネストしたクラスに最適なシナリオです。TaskProjectのコンテキスト内でのみ意味を持つため、コードを整理し、グローバルnamespaceを汚染しないように、その内部にネストします。

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

  • Project.h:ネストしたTaskクラスを含むProjectクラスをdefineします。

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

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

    TaskProjectの内部にネストされているため、Projectクラスはタスクを直接扱えます。destructordynamically割り当てられたタスクをcleanアップすることを忘れないでください。

  • main.cpp:入力からプロジェクト名と2つのタスク名(合計3行)を読み取って、すべてを組み合わせます。given名前でProjectを作成し、両方のタスクを追加してから、initialステータスを表示します。最初のタスクを完了し、changeを示すためにステータスをもう一度表示します。

    displayStatus()の出力形式は次のようになります。

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

    各タスクのステータスに応じて、[complete]または[incomplete]を使用します。

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

自分で試してみよう

#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腕試し

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

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

自分で練習してみよう: C++オンラインコンパイラ