Menu
Coddy logo textTech

Classi annidate e interne

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 38 di 104.

Una classe annidata è una classe definita all'interno di un'altra classe. Questa tecnica aiuta a organizzare il codice raggruppando insieme tipi correlati e può migliorare l'incapsulamento nascondendo i dettagli di implementazione.

class LinkedList {
public:
    class Node {    // Classe annidata
        int data;
        Node* next;
    public:
        Node(int d) : data(d), next(nullptr) {}
        friend class LinkedList;
    };
    
private:
    Node* head;
    
public:
    LinkedList() : head(nullptr) {}
};

La classe annidata Node è strettamente legata a LinkedList: ha senso solo in quel contesto. Annidandola, segnaliamo questa relazione ed evitiamo di inquinare lo spazio dei nomi globale con un nome generico come "Node".

Le classi annidate seguono le stesse regole di accesso che hai imparato. Una classe annidata dichiarata nella sezione privata è accessibile solo all'interno della classe esterna.

Quando viene dichiarato pubblico, il codice esterno può usarlo con l'operatore di ambito:

LinkedList::Node node(42);    // Solo se Node è public

Un dettaglio importante riguardo alla direzione: una classe annidata è un membro della classe contenitore e ha gli stessi diritti di accesso di qualsiasi altro membro, quindi può accedere ai membri privati della classe contenitore senza una dichiarazione friend. Il contrario, però, non è automatico: la classe contenitore non ha accesso ai membri privati della classe annidata.

Ecco perché Node dichiara friend class LinkedList; nell'esempio qui sopra: la dichiarazione friend concede alla LinkedList che la contiene l'accesso ai membri privati di Node, l'unica direzione che non è automatica.

challenge icon

Sfida

Facile

Costruiamo un semplice sistema di gestione delle attività in cui le attività sono organizzate all'interno di un progetto. È uno scenario perfetto per le classi annidate: una Task ha senso solo nel contesto di un Project, quindi la annideremo al suo interno per mantenere organizzato il codice ed evitare di inquinare lo spazio dei nomi globale.

Creerai due file per organizzare il codice:

  • Project.h: definisci una classe Project che contiene una classe Task annidata.

    La classe Task annidata deve essere dichiarata nella sezione public di Project, così potrà essere utilizzata dall'esterno. Deve memorizzare il nome di un'attività (stringa) e il suo stato di completamento (bool). Aggiungi un costruttore che accetti il nome e imposti l'attività come incompleta per impostazione predefinita. Includi i metodi complete() per contrassegnarla come completata, isComplete() per verificarne lo stato e getName() per recuperare il nome.

    La classe Project stessa deve memorizzare il nome di un progetto (stringa) e una raccolta di puntatori a Task. Fornisci un costruttore che accetti il nome del progetto, un metodo addTask(const std::string& taskName) che crei una nuova attività e la aggiunga al progetto, un metodo completeTask(const std::string& taskName) che trovi e completi un'attività in base al nome e un metodo displayStatus() che mostri il nome del progetto seguito dallo stato di ciascuna attività.

    Poiché Task è annidata all'interno di Project, la classe Project può lavorare direttamente con le attività. Non dimenticare di liberare le attività allocate dinamicamente nel distruttore.

  • main.cpp: metti insieme tutti gli elementi leggendo da input il nome di un progetto e i nomi di due attività (tre righe in totale). Crea un Project con il nome fornito, aggiungici entrambe le attività e poi mostra lo stato iniziale. Completa la prima attività e mostra di nuovo lo stato per evidenziare il cambiamento.

    Il formato di output di displayStatus() deve essere:

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

    Usa [complete] o [incomplete] in base allo stato di ciascuna attività.

Questa sfida mostra come le classi annidate aiutino a organizzare tipi correlati: la classe Task è strettamente legata a Project e non avrebbe senso da sola. Annidandola, rendiamo chiara questa relazione nella struttura del codice.

Provalo tu

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

using namespace std;

int main() {
    // Leggi l'input
    string projectName;
    string task1Name;
    string task2Name;
    
    getline(cin, projectName);
    getline(cin, task1Name);
    getline(cin, task2Name);
    
    // TODO: Crea un Project con il nome fornito
    
    // TODO: Aggiungi entrambe le attività al progetto
    
    // TODO: Mostra lo stato iniziale
    
    // TODO: Completa la prima attività
    
    // TODO: Mostra di nuovo lo stato per evidenziare il cambiamento
    
    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C++ online