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. Esta técnica ajuda a organizar o código agrupando tipos relacionados e pode melhorar 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 está fortemente acoplada à LinkedList - ela só faz sentido nesse contexto. Ao aninhá-la, sinalizamos esse relacionamento e evitamos poluir o namespace global com um nome genérico como "Node".

Classes aninhadas seguem as mesmas regras de acesso que você aprendeu. Uma classe aninhada declarada na seção private é acessível apenas dentro da classe externa.

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

LinkedList::Node node(42);    // Apenas 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, ela pode acessar os membros privados da classe envolvente sem nenhuma declaração friend. O inverso não é automático, no entanto — 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 à LinkedList envolvente acesso aos membros privados de Node, a única direção que não é automática.

challenge icon

Desafio

Fácil

Vamos construir um sistema simples de gerenciamento de tarefas onde as tarefas são organizadas dentro de um projeto. Este é um cenário perfeito para classes aninhadas — uma Task só faz sentido dentro do contexto de um Project, então vamos aninhá-la dentro 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 Task aninhada.

    Sua classe Task aninhada deve ser declarada na seção public de Project para que possa ser acessada de fora. 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 recuperar o nome.

    A classe Project em si 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 cria uma nova tarefa e a adiciona ao projeto, um método completeTask(const std::string& taskName) que encontra e conclui uma tarefa pelo nome, e um método displayStatus() que mostra o nome do projeto seguido pelo status de cada tarefa.

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

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

    O formato de saída para 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 classes aninhadas ajudam a organizar tipos relacionados — a classe Task está fortemente acoplada ao Project e não faria sentido sozinha. Ao aninhá-la, sinalizamos esse relacionamento claramente em nossa estrutura de 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: Criar um Projeto com o nome fornecido
    
    // TODO: Adicionar ambas as tarefas ao projeto
    
    // TODO: Exibir o status inicial
    
    // TODO: Concluir a primeira tarefa
    
    // TODO: Exibir o status novamente para mostrar a alteração
    
    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