Menu
Coddy logo textTech

Composição vs Herança

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 76 de 104.

Ao projetar relacionamentos entre classes, você tem duas opções principais: herança ("é um") e composição ("tem um"). Escolher a abordagem correta impacta significativamente a flexibilidade e a manutenibilidade do seu código.

Herança cria um acoplamento forte entre classes. Um Car que herda de Vehicle está permanentemente vinculado a esse relacionamento:

class Vehicle {
public:
    virtual void start() { std::cout << "Starting vehicle\n"; }
};

class Car : public Vehicle {
public:
    void start() override { std::cout << "Starting car\n"; }
};

Composição incorpora objetos como membros, criando um relacionamento mais flexível. Um Car tem um Engine em vez de ser um motor:

class Engine {
public:
    void start() { std::cout << "Engine running\n"; }
};

class Car {
private:
    Engine engine;  // Car TEM um Motor
public:
    void start() { engine.start(); }
};

A principal vantagem da composição é a flexibilidade. Você pode facilmente trocar componentes, alterar o comportamento em tempo de execução ou combinar múltiplas capacidades sem as restrições de uma hierarquia de classes rígida. O design moderno de C++ favorece a composição em vez da herança na maioria dos casos.

Use herança quando houver um relacionamento genuíno "é um" (is-a) e você precisar de polimorfismo. Use composição quando quiser reutilizar funcionalidades ou quando o relacionamento for melhor descrito como "tem um" (has-a) ou "usa um" (uses-a).

challenge icon

Desafio

Fácil

Vamos construir um simulador de sistema de computador que demonstra quando usar composição em vez de herança. Você modelará um computador que possui componentes (composição) em vez de ser um componente, mostrando como a composição oferece flexibilidade para trocar peças em tempo de execução.

Você organizará seu código em três arquivos:

  • Components.h: Defina os componentes individuais que um computador pode conter.

    Crie uma classe CPU com um std::string model e int cores privados. Forneça um construtor que receba ambos os valores, um método process() que imprima CPU [model] processing with [cores] cores, e um método getModel().

    Crie uma classe Memory com um int sizeGB privado. Forneça um construtor, um método load() que imprima Loading data into [sizeGB]GB RAM, e um método getSize().

    Crie uma classe Storage com um std::string type privado (como "SSD" ou "HDD") e int capacityGB. Forneça um construtor, um método read() que imprima Reading from [capacityGB]GB [type], e métodos getter para ambos os campos.

  • Computer.h: Defina uma classe Computer que use composição para combinar componentes.

    Seu Computer deve ter objetos membros privados: uma CPU, uma Memory e um Storage. Use a lista de inicialização do construtor para inicializar esses componentes a partir dos parâmetros.

    Implemente estes métodos:

    • boot() — imprime Booting computer..., depois chama load() na memória, read() no armazenamento e process() na CPU, cada um em linhas separadas
    • specs() — imprime as especificações do computador neste formato:
      Computer Specs:
      - CPU: [model] ([cores] cores)
      - RAM: [size]GB
      - Storage: [capacity]GB [type]
  • main.cpp: Leia seis entradas (cada uma em uma linha separada):
    1. Nome do modelo da CPU (string)
    2. Número de núcleos da CPU (inteiro)
    3. Tamanho da memória em GB (inteiro)
    4. Tipo de armazenamento (string, por exemplo, "SSD")
    5. Capacidade de armazenamento em GB (inteiro)
    6. Um comando: "boot" ou "specs"

    Crie os objetos componentes e, em seguida, crie um Computer usando composição. Com base no comando, chame boot() ou specs().

Por exemplo, com as entradas Intel i7, 8, 16, SSD, 512 e boot:

Booting computer...
Loading data into 16GB RAM
Reading from 512GB SSD
CPU Intel i7 processing with 8 cores

Com as entradas AMD Ryzen, 6, 32, HDD, 1000 e specs:

Computer Specs:
- CPU: AMD Ryzen (6 cores)
- RAM: 32GB
- Storage: 1000GB HDD

Observe como a classe Computer não herda de nenhum componente — ela os contém. Esse relacionamento "tem-um" significa que você poderia facilmente criar computadores com diferentes combinações de componentes, ou até mesmo trocar componentes mais tarde se adicionasse métodos setter. Essa flexibilidade é a principal vantagem da composição sobre a herança.

Folha de consulta

Ao projetar relacionamentos entre classes, escolha entre herança ("é-um") e composição ("tem-um").

A Herança cria um acoplamento forte entre as classes:

class Vehicle {
public:
    virtual void start() { std::cout << "Starting vehicle\n"; }
};

class Car : public Vehicle {
public:
    void start() override { std::cout << "Starting car\n"; }
};

A Composição incorpora objetos como membros, criando relacionamentos flexíveis:

class Engine {
public:
    void start() { std::cout << "Engine running\n"; }
};

class Car {
private:
    Engine engine;  // Car TEM um Engine
public:
    void start() { engine.start(); }
};

Quando usar cada uma:

  • Use herança para relacionamentos genuínos do tipo "é-um" quando você precisar de polimorfismo
  • Use composição para reutilizar funcionalidade ou para relacionamentos do tipo "tem-um"/"usa-um"
  • O design moderno de C++ favorece a composição por sua flexibilidade — você pode trocar componentes, alterar o comportamento em tempo de execução e combinar recursos sem hierarquias rígidas

Experimente você mesmo

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

using namespace std;

int main() {
    // Ler as entradas
    string cpuModel;
    getline(cin, cpuModel);  // Nome do modelo da CPU (pode conter espaços)
    
    int cpuCores;
    cin >> cpuCores;  // Número de núcleos da CPU
    
    int memorySize;
    cin >> memorySize;  // Tamanho da memória em GB
    
    string storageType;
    cin >> storageType;  // Tipo de armazenamento (ex: "SSD")
    
    int storageCapacity;
    cin >> storageCapacity;  // Capacidade de armazenamento em GB
    
    string command;
    cin >> command;  // Comando: "boot" ou "specs"

    // TODO: Criar objetos de componentes (CPU, Memory, Storage)
    
    // TODO: Criar um objeto Computer usando composição
    
    // TODO: Com base no comando, chamar boot() ou specs()

    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