Menu
Coddy logo textTech

Klasy zagnieżdżone i wewnętrzne

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 38 z 104.

Klasa zagnieżdżona to klasa zdefiniowana wewnątrz innej klasy. Ta technika pomaga organizować kod poprzez grupowanie powiązanych typów i może zwiększyć hermetyzację przez ukrywanie szczegółów implementacji.

class LinkedList {
public:
    class Node {    // Klasa zagnieżdżona
        int data;
        Node* next;
    public:
        Node(int d) : data(d), next(nullptr) {}
        friend class LinkedList;
    };
    
private:
    Node* head;
    
public:
    LinkedList() : head(nullptr) {}
};

Zagnieżdżona klasa Node jest ściśle powiązana z LinkedList — ma sens tylko w tym kontekście. Zagnieżdżając ją, sygnalizujemy tę relację i unikamy zaśmiecania globalnej przestrzeni nazw ogólną nazwą, taką jak „Node”.

Klasy zagnieżdżone podlegają tym samym zasadom dostępu, których się nauczyłeś. Klasa zagnieżdżona zadeklarowana w sekcji prywatnej jest dostępna tylko w obrębie klasy zewnętrznej.

Gdy zostanie zadeklarowany jako publiczny, kod zewnętrzny może go używać za pomocą operatora zakresu:

LinkedList::Node node(42);    // Tylko jeśli Node jest publiczna

Ważny szczegół dotyczący kierunku dostępu: klasa zagnieżdżona jest składową klasy zewnętrznej i ma takie same prawa dostępu jak każda inna składowa, więc może uzyskiwać dostęp do prywatnych składowych klasy zewnętrznej bez deklaracji friend. Nie działa to jednak automatycznie w odwrotną stronę: klasa zewnętrzna nie ma dostępu do prywatnych składowych klasy zagnieżdżonej.

Dlatego Node deklaruje friend class LinkedList; w powyższym przykładzie: deklaracja friend przyznaje otaczającej klasie LinkedList dostęp do prywatnych składowych Node, co nie dzieje się automatycznie w tym jednym kierunku.

challenge icon

Wyzwanie

Łatwy

Zbudujmy prosty system zarządzania zadaniami, w którym zadania są zorganizowane w ramach projektu. To idealny przykład zastosowania klas zagnieżdżonych: Task ma sens tylko w kontekście Project, dlatego zagnieździmy ją w tej klasie, aby uporządkować kod i uniknąć zaśmiecania globalnej przestrzeni nazw.

Utworzysz dwa pliki, aby uporządkować kod:

  • Project.h: Zdefiniuj klasę Project, która zawiera zagnieżdżoną klasę Task.

    Zagnieżdżona klasa Task powinna być zadeklarowana w sekcji public klasy Project, aby można było uzyskać do niej dostęp z zewnątrz. Powinna przechowywać nazwę zadania (string) i stan jego ukończenia (bool). Dodaj konstruktor, który przyjmuje nazwę i domyślnie ustawia zadanie jako nieukończone. Dodaj metody complete(), która oznacza zadanie jako ukończone, isComplete(), która sprawdza jego stan, oraz getName(), która pobiera nazwę.

    Sama klasa Project powinna przechowywać nazwę projektu (string) i kolekcję wskaźników Task. Dodaj konstruktor przyjmujący nazwę projektu, metodę addTask(const std::string& taskName), która tworzy nowe zadanie i dodaje je do projektu, metodę completeTask(const std::string& taskName), która wyszukuje zadanie po nazwie i oznacza je jako ukończone, oraz metodę displayStatus(), która wyświetla nazwę projektu, a następnie stan każdego zadania.

    Ponieważ Task jest zagnieżdżona w Project, klasa Project może bezpośrednio obsługiwać zadania. Nie zapomnij zwolnić pamięci przydzielonej dynamicznie na zadania w destruktorze.

  • main.cpp: Połącz wszystkie elementy, odczytując z wejścia nazwę projektu i nazwy dwóch zadań (łącznie trzy wiersze). Utwórz Project o podanej nazwie, dodaj do niego oba zadania, a następnie wyświetl początkowy stan. Oznacz pierwsze zadanie jako ukończone i ponownie wyświetl stan, aby pokazać zmianę.

    Format wyjściowy metody displayStatus() powinien wyglądać następująco:

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

    Użyj [complete] lub [incomplete] w zależności od stanu każdego zadania.

To wyzwanie pokazuje, jak klasy zagnieżdżone pomagają porządkować powiązane typy: klasa Task jest ściśle powiązana z Project i sama w sobie nie miałaby sensu. Zagnieżdżając ją, jasno sygnalizujemy tę relację w strukturze kodu.

Spróbuj swoich sił

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

using namespace std;

int main() {
    // Odczytaj dane wejściowe
    string projectName;
    string task1Name;
    string task2Name;
    
    getline(cin, projectName);
    getline(cin, task1Name);
    getline(cin, task2Name);
    
    // TODO: Utwórz obiekt Project o podanej nazwie
    
    // TODO: Dodaj oba zadania do projektu
    
    // TODO: Wyświetl początkowy stan
    
    // TODO: Oznacz pierwsze zadanie jako ukończone
    
    // TODO: Wyświetl stan ponownie, aby pokazać zmianę
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online