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 adecuado influye significativamente en la flexibilidad y la facilidad de mantenimiento de tu código.

La herencia crea un acoplamiento estrecho entre clases. Un Car que hereda de Vehicle queda vinculado permanentemente 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"; }
};

Composición integra 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;  // Car TIENE un Engine
public:
    void start() { engine.start(); }
};

La principal ventaja de la composición es la flexibilidad. Puedes intercambiar componentes fácilmente, cambiar el comportamiento en tiempo de ejecución o combinar varias capacidades sin las limitaciones 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 exista una relación genuina de «is-a» y necesites polimorfismo. Usa la composición cuando quieras reutilizar funcionalidad o cuando la relación se describa mejor como «has-a» o «uses-a».

challenge icon

Desafío

Fácil

Construyamos un simulador de sistemas informáticos que demuestre cuándo usar composición en lugar de herencia. Modelarás un ordenador 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 puede contener un ordenador.

    Crea una clase CPU con un std::string model y un int cores privados. Proporciona un constructor que acepte 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. 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 use composición para combinar componentes.

    Tu Computer debe tener objetos miembro privados: un CPU, una Memory y un Storage. Usa 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..., después llama a load() en la memoria, a read() en el almacenamiento y a process() en la CPU, cada uno en una línea separada
    • specs(): imprime las especificaciones del ordenador con 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 la CPU (cadena)
    2. Número de núcleos de la CPU (entero)
    3. Tamaño de la memoria en GB (entero)
    4. Tipo de almacenamiento (cadena, por ejemplo, "SSD")
    5. Capacidad del almacenamiento en GB (entero)
    6. Un comando: "boot" o "specs"

    Crea los objetos de los componentes y, después, crea un Computer usando composición. Según 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 que la clase Computer no hereda de ningún componente. Los contiene. Esta relación de tipo "tiene-un" significa que podrías crear fácilmente ordenadores con diferentes combinaciones de componentes, o incluso intercambiar componentes más adelante si añadieras métodos setter. Esta flexibilidad es la principal ventaja de la composición frente a la herencia.

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 (p. ej., "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: Según 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

Practica por tu cuenta: Compilador de C++ online