Menu
Coddy logo textTech

Classes aninhadas e internas

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 38 de 104.

Uma classe aninhada é uma classe definida dentro de outra classe. Essa técnica ajuda a organizar o código agrupando tipos relacionados e pode aprimorar o encapsulamento ao ocultar detalhes de implementação.

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

A classe aninhada Node é fortemente acoplada a LinkedList — ela só faz sentido nesse contexto. Ao aninhá-la, sinalizamos essa relação e evitamos poluir o namespace global com um nome genérico como "Node".

As classes aninhadas seguem as mesmas regras de acesso que você aprendeu. Uma classe aninhada declarada na seção privada só pode ser acessada dentro da classe externa.

Quando declarado como público, o código externo pode usá-lo com o operador de escopo:

LinkedList::Node node(42);    // Somente se Node for público

Um detalhe importante sobre a direção: uma classe aninhada é um membro da classe envolvente e tem os mesmos direitos de acesso que qualquer outro membro, portanto pode acessar os membros privados da classe envolvente sem uma declaração friend. O inverso não é automático, porém: a classe envolvente não tem acesso aos membros privados da classe aninhada.

É por isso que Node declara friend class LinkedList; no exemplo acima: a declaração friend concede ao LinkedList que o envolve acesso aos membros privados de Node, a única direção que não é automática.

challenge icon

Desafio

Fácil

Vamos criar um sistema simples de gerenciamento de tarefas em que as tarefas são organizadas dentro de um projeto. Este é um cenário perfeito para classes aninhadas: uma Task só faz sentido no contexto de uma Project, então vamos aninhá-la dentro dela para manter nosso código organizado e evitar poluir o namespace global.

Você criará dois arquivos para organizar seu código:

  • Project.h: Defina uma classe Project que contenha uma classe aninhada Task.

    Sua classe aninhada Task deve ser declarada na seção pública de Project para que possa ser acessada externamente. Ela deve armazenar um nome de tarefa (string) e um status de conclusão (bool). Dê a ela um construtor que receba o nome e defina a tarefa como incompleta por padrão. Inclua os métodos complete() para marcá-la como concluída, isComplete() para verificar seu status e getName() para obter o nome.

    A própria classe Project deve armazenar um nome de projeto (string) e uma coleção de ponteiros para Task. Forneça um construtor que receba o nome do projeto, um método addTask(const std::string& taskName) que crie uma nova tarefa e a adicione ao projeto, um método completeTask(const std::string& taskName) que encontre e conclua uma tarefa pelo nome e um método displayStatus() que mostre o nome do projeto seguido pelo status de cada tarefa.

    Como Task está aninhada dentro de Project, a classe Project pode trabalhar diretamente com as tarefas. Não se esqueça de liberar as tarefas alocadas dinamicamente no destrutor.

  • main.cpp: Reúna tudo lendo um nome de projeto e dois nomes de tarefa da entrada (três linhas ao todo). Crie uma Project com o nome fornecido, adicione ambas as tarefas a ela e, em seguida, exiba o status inicial. Conclua a primeira tarefa e exiba o status novamente para mostrar a alteração.

    O formato de saída de displayStatus() deve ser:

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

    Use [complete] ou [incomplete] com base no status de cada tarefa.

Este desafio demonstra como as classes aninhadas ajudam a organizar tipos relacionados: a classe Task é fortemente acoplada a Project e não faria sentido por conta própria. Ao aninhá-la, sinalizamos claramente essa relação na estrutura do nosso código.

Experimente você mesmo

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

using namespace std;

int main() {
    // Ler entrada
    string projectName;
    string task1Name;
    string task2Name;
    
    getline(cin, projectName);
    getline(cin, task1Name);
    getline(cin, task2Name);
    
    // TODO: Crie um Project com o nome fornecido
    
    // TODO: Adicione ambas as tarefas ao projeto
    
    // TODO: Exiba o status inicial
    
    // TODO: Conclua a primeira tarefa
    
    // TODO: Exiba o status novamente para mostrar a mudança
    
    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de C++ online