Menu
Coddy logo textTech

Composición vs. Herencia

Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 76 de 104.

Al diseñar relaciones entre clases, tienes dos opciones principales: herencia ("es-un") y composición ("tiene-un"). Elegir el enfoque correcto impacta significativamente la flexibilidad y el mantenimiento de tu código.

La herencia crea un acoplamiento fuerte entre clases. Un Car que hereda de Vehicle está permanentemente ligado a esa relación:

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

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

La composición incrusta objetos como miembros, creando una relación más flexible. Un Car tiene un Engine en lugar de ser un motor:

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

class Car {
private:
    Engine engine;  // El Coche TIENE un Motor
public:
    void start() { engine.start(); }
};

La ventaja clave de la composición es la flexibilidad. Puedes intercambiar componentes fácilmente, cambiar el comportamiento en tiempo de ejecución o combinar múltiples capacidades sin las restricciones de una jerarquía de clases rígida. El diseño moderno de C++ favorece la composición sobre la herencia en la mayoría de los casos.

Usa la herencia cuando haya una relación genuina de tipo "es-un" y necesites polimorfismo. Usa la composición cuando quieras reutilizar funcionalidad o cuando la relación se describa mejor como "tiene-un" o "usa-un".

challenge icon

Desafío

Fácil

Vamos a construir un simulador de sistema informático que demuestre cuándo usar composición en lugar de herencia. Modelarás una computadora que tiene componentes (composición) en lugar de ser un componente, mostrando cómo la composición proporciona flexibilidad para intercambiar piezas en tiempo de ejecución.

Organizarás tu código en tres archivos:

  • Components.h: Define los componentes individuales que una computadora puede contener.

    Crea una clase CPU con un std::string model y un int cores privados. Proporciona un constructor que reciba ambos valores, un método process() que imprima CPU [model] processing with [cores] cores, y un método getModel().

    Crea una clase Memory con un int sizeGB privado. Proporciona un constructor, un método load() que imprima Loading data into [sizeGB]GB RAM, y un método getSize().

    Crea una clase Storage con un std::string type privado (como "SSD" o "HDD") y un int capacityGB privado. Proporciona un constructor, un método read() que imprima Reading from [capacityGB]GB [type], y métodos getter para ambos campos.

  • Computer.h: Define una clase Computer que utiliza la composición para combinar componentes.

    Tu Computer debe tener objetos miembros privados: un CPU, una Memory y un Storage. Utiliza la lista de inicialización del constructor para inicializar estos componentes a partir de los parámetros.

    Implementa estos métodos:

    • boot() — imprime Booting computer..., luego llama a load() en la memoria, read() en el almacenamiento y process() en la CPU, cada uno en líneas separadas.
    • specs() — imprime las especificaciones de la computadora en este formato:
      Computer Specs:
      - CPU: [model] ([cores] cores)
      - RAM: [size]GB
      - Storage: [capacity]GB [type]
  • main.cpp: Lee seis entradas (cada una en una línea separada):
    1. Nombre del modelo de CPU (string)
    2. Número de núcleos de CPU (integer)
    3. Tamaño de la memoria en GB (integer)
    4. Tipo de almacenamiento (string, por ejemplo, "SSD")
    5. Capacidad de almacenamiento en GB (integer)
    6. Un comando: ya sea "boot" o "specs"

    Crea los objetos de los componentes, luego crea un Computer usando composición. Basándote en el comando, llama a boot() o a specs().

Por ejemplo, con las entradas Intel i7, 8, 16, SSD, 512, y boot:

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

Con las entradas AMD Ryzen, 6, 32, HDD, 1000, y specs:

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

Observa cómo la clase Computer no hereda de ningún componente; los contiene. Esta relación de "tiene-un" significa que podrías crear fácilmente computadoras con diferentes combinaciones de componentes, o incluso intercambiar componentes más tarde si añadieras métodos setter. Esta flexibilidad es la ventaja clave de la composición sobre la herencia.

Hoja de referencia

Al diseñar relaciones entre clases, elija entre herencia ("es-un") y composición ("tiene-un").

La herencia crea un acoplamiento fuerte entre clases:

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

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

La composición incrusta objetos como miembros, creando relaciones flexibles:

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

class Car {
private:
    Engine engine;  // El Car TIENE UN Engine
public:
    void start() { engine.start(); }
};

Cuándo usar cada una:

  • Use herencia para relaciones genuinas de tipo "es-un" cuando necesite polimorfismo
  • Use composición para reutilizar funcionalidad o para relaciones de tipo "tiene-un"/"usa-un"
  • El diseño moderno de C++ favorece la composición por su flexibilidad: puede intercambiar componentes, cambiar el comportamiento en tiempo de ejecución y combinar capacidades sin jerarquías rígidas

Pruébalo tú mismo

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

using namespace std;

int main() {
    // Leer entradas
    string cpuModel;
    getline(cin, cpuModel);  // Nombre del modelo de CPU (puede contener espacios)
    
    int cpuCores;
    cin >> cpuCores;  // Número de núcleos de CPU
    
    int memorySize;
    cin >> memorySize;  // Tamaño de la memoria en GB
    
    string storageType;
    cin >> storageType;  // Tipo de almacenamiento (por ejemplo, "SSD")
    
    int storageCapacity;
    cin >> storageCapacity;  // Capacidad de almacenamiento en GB
    
    string command;
    cin >> command;  // Comando: "boot" o "specs"

    // TODO: Crear objetos de componentes (CPU, Memory, Storage)
    
    // TODO: Crear un objeto Computer usando composición
    
    // TODO: Basado en el comando, llamar a boot() o specs()

    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos