Verschachtelte & innere Klassen
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 38 von 104.
Eine geschachtelte Klasse ist eine Klasse, die innerhalb einer anderen Klasse definiert ist. Diese Technik hilft dabei, Code zu organisieren, indem verwandte Typen gruppiert werden, und kann die Kapselung verbessern, indem Implementierungsdetails verborgen werden.
class LinkedList {
public:
class Node { // Verschachtelte Klasse
int data;
Node* next;
public:
Node(int d) : data(d), next(nullptr) {}
friend class LinkedList;
};
private:
Node* head;
public:
LinkedList() : head(nullptr) {}
};Die verschachtelte Klasse Node ist eng an LinkedList gekoppelt – sie ergibt nur in diesem Kontext Sinn. Durch das Verschachteln signalisieren wir diese Beziehung und vermeiden es, den globalen Namensraum mit einem generischen Namen wie „Node“ zu verunreinigen.
Verschachtelte Klassen folgen denselben Zugriffsregeln, die Sie gelernt haben. Eine im privaten Bereich deklarierte verschachtelte Klasse ist nur innerhalb der äußeren Klasse zugänglich.
Wenn als public deklariert, kann externer Code ihn mit dem Scope-Operator verwenden:
LinkedList::Node node(42); // Nur wenn Node öffentlich istEin wichtiges Detail: Die verschachtelte Klasse hat nicht automatisch Zugriff auf die privaten Member der äußeren Klasse. Es handelt sich um separate Klassen, die zufällig einen Namensraum teilen.
Wenn die verschachtelte Klasse Zugriff benötigt, müssen Sie sie als friend deklarieren, wie im obigen Beispiel gezeigt.
Aufgabe
EinfachLassen Sie uns ein einfaches Aufgabenverwaltungssystem erstellen, bei dem Aufgaben innerhalb eines Projekts organisiert sind. Dies ist ein perfektes Szenario für verschachtelte Klassen — eine Task ist nur im Kontext eines Project sinnvoll, daher werden wir sie darin verschachteln, um unseren Code organisiert zu halten und eine Verunreinigung des globalen Namensraums zu vermeiden.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
Project.h: Definieren Sie eineProject-Klasse, die eine verschachtelteTask-Klasse enthält.Ihre verschachtelte
Task-Klasse sollte im public-Bereich vonProjectdeklariert werden, damit von außen darauf zugegriffen werden kann. Sie sollte einen Aufgabennamen (string) und einen Abschlussstatus (bool) speichern. Geben Sie ihr einen Konstruktor, der den Namen entgegennimmt und die Aufgabe standardmäßig als unvollständig markiert. Fügen Sie die Methodencomplete()hinzu, um sie als erledigt zu markieren,isComplete(), um ihren Status zu prüfen, undgetName(), um den Namen abzurufen.Die
Project-Klasse selbst sollte einen Projektnamen (string) und eine Sammlung vonTask-Pointern speichern. Stellen Sie einen Konstruktor bereit, der den Projektnamen entgegennimmt, eine MethodeaddTask(const std::string& taskName), die eine neue Aufgabe erstellt und zum Projekt hinzufügt, eine MethodecompleteTask(const std::string& taskName), die eine Aufgabe anhand des Namens findet und abschließt, und eine MethodedisplayStatus(), die den Projektnamen gefolgt vom Status jeder Aufgabe anzeigt.Da
Taskinnerhalb vonProjectverschachtelt ist, kann dieProject-Klasse direkt mit Aufgaben arbeiten. Vergessen Sie nicht, dynamisch zugewiesene Aufgaben im Destruktor zu bereinigen.main.cpp: Führen Sie alles zusammen, indem Sie einen Projektnamen und zwei Aufgabennamen aus der Eingabe lesen (insgesamt drei Zeilen). Erstellen Sie einProjectmit dem angegebenen Namen, fügen Sie beide Aufgaben hinzu und zeigen Sie dann den ursprünglichen Status an. Schließen Sie die erste Aufgabe ab und zeigen Sie den Status erneut an, um die Änderung zu verdeutlichen.Das Ausgabeformat für
displayStatus()sollte wie folgt aussehen:Project: <project_name> - <task_name>: [incomplete] - <task_name>: [complete]Verwenden Sie
[complete]oder[incomplete]basierend auf dem Status jeder Aufgabe.
Diese Herausforderung zeigt, wie verschachtelte Klassen helfen, verwandte Typen zu organisieren — die Task-Klasse ist eng mit Project gekoppelt und wäre für sich allein nicht sinnvoll. Durch das Verschachteln signalisieren wir diese Beziehung klar in unserer Codestruktur.
Spickzettel
Eine geschachtelte Klasse (nested class) ist eine Klasse, die innerhalb einer anderen Klasse definiert ist. Sie hilft dabei, Code zu organisieren, indem sie verwandte Typen gruppiert, und verbessert die Kapselung.
class LinkedList {
public:
class Node { // Geschachtelte Klasse
int data;
Node* next;
public:
Node(int d) : data(d), next(nullptr) {}
friend class LinkedList;
};
private:
Node* head;
public:
LinkedList() : head(nullptr) {}
};Geschachtelte Klassen folgen den Standard-Zugriffsregeln. Eine geschachtelte Klasse im privaten Bereich ist nur innerhalb der äußeren Klasse zugänglich. Wenn sie als öffentlich (public) deklariert ist, kann externer Code sie mit dem Bereichsauflösungsoperator verwenden:
LinkedList::Node node(42); // Nur wenn Node öffentlich istDie geschachtelte Klasse hat nicht automatisch Zugriff auf die privaten Member der äußeren Klasse. Wenn Zugriff benötigt wird, deklarieren Sie sie als Friend:
friend class LinkedList;Probier es selbst
#include <iostream>
#include <string>
#include "Project.h"
using namespace std;
int main() {
// Eingabe lesen
string projectName;
string task1Name;
string task2Name;
getline(cin, projectName);
getline(cin, task1Name);
getline(cin, task2Name);
// TODO: Erstellen Sie ein Projekt mit dem angegebenen Namen
// TODO: Fügen Sie beide Aufgaben zum Projekt hinzu
// TODO: Zeigen Sie den ursprünglichen Status an
// TODO: Schließen Sie die erste Aufgabe ab
// TODO: Zeigen Sie den Status erneut an, um die Änderung zu sehen
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienC++ Build & KompilierungHeader-Dateien & QuelldateienNamensräume & GültigkeitsbereicheEinführung in OOP in C++Klassen vs. ObjekteDer 'this'-PointerMethoden (Elementfunktionen)Attribute (Datenelemente)Grundlagen zu Ctors & DtorsRückblick - Einfacher Taschenrechner4Klasseneigenschaften
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen & KlassenZusammenfassung - Bankkonto-Manager7Vererbung
Grundlagen der VererbungZugriffsstufen bei VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick - Mitarbeiter-Hierarchie2Speicherverwaltung
Stack vs. Heap SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Smart Pointers in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsspezifizierer in C++Zugriffsspezifizierer im DetailInformation HidingStruct vs. ClassVerschachtelte & innere KlassenRückblick - Studentenverwaltungssystem8Polymorphie
Kompilierzeit- vs. Laufzeit-PolymorphieFunktionsüberladungVirtuelle Funktionen – WiederholungRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIZusammenfassung – Formen-Rechner3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorVerschiebekonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktoren im DetailRule of Three / Five / ZeroZusammenfassung - String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladen der [] und () OperatorenTypumwandlungsoperatorenRückblick - Matrix-Klasse9Templates
FunktionstemplatesKlassentemplatesTemplate-SpezialisierungVariadische TemplatesSFINAE & Type Traits GrundlagenRückblick - Generische Container