Menu
Coddy logo textTech

Herencia múltiple

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

C++ permite que una clase herede de múltiples clases base simultáneamente. Esto se llama herencia múltiple y permite combinar características de diferentes jerarquías de clases.

Para heredar de múltiples clases, sepárelas con comas:

class Printer {
public:
    void print() {
        std::cout << "Printing document" << std::endl;
    }
};

class Scanner {
public:
    void scan() {
        std::cout << "Scanning document" << std::endl;
    }
};

class MultiFunctionDevice : public Printer, public Scanner {
public:
    void copy() {
        scan();
        print();
    }
};

La clase MultiFunctionDevice ahora tiene acceso a los métodos de tanto Printer como Scanner:

MultiFunctionDevice mfd;
mfd.print();  // De Printer
mfd.scan();   // De Scanner
mfd.copy();   // Su propio método

Los constructores se llaman en el orden en que las clases base aparecen en la declaración de herencia (de izquierda a derecha), y los destructores en orden inverso. Puedes pasar argumentos a cada constructor base en la lista de inicialización:

class MultiFunctionDevice : public Printer, public Scanner {
public:
    MultiFunctionDevice() : Printer(), Scanner() {}
};

Surge un problema potencial cuando ambas clases base tienen un miembro con el mismo nombre. Esto crea ambigüedad, y debes usar el operador de resolución de ámbito para especificar a cuál te refieres:

class A { public: void show() {} };
class B { public: void show() {} };
class C : public A, public B {};

C obj;
obj.A::show();  // Llama a la versión de A
obj.B::show();  // Llama a la versión de B

La herencia múltiple es poderosa pero puede dar lugar a situaciones complejas, especialmente cuando las clases base comparten un ancestro común. Exploraremos ese desafío en la próxima lección.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de dispositivos para el hogar inteligente que combine capacidades de múltiples clases base utilizando herencia múltiple. Crearás dispositivos que puedan conectarse a WiFi y ser controlados por voz, y luego combinarás estas características en un altavoz inteligente unificado.

Organizarás tu código en tres archivos:

  • WiFiDevice.h: Define una clase WiFiDevice que represente cualquier dispositivo capaz de conectarse a una red:
    • Un miembro protegido std::string networkName
    • Un constructor que reciba un nombre de red y lo almacene
    • Un método público connect() que imprima: Connecting to WiFi: <networkName>
    • Un método público status() que imprima: WiFi Status: Connected
  • VoiceControl.h: Define una clase VoiceControl que represente cualquier dispositivo con capacidades de voz:
    • Un miembro protegido std::string assistantName
    • Un constructor que reciba un nombre de asistente y lo almacene
    • Un método público listen() que imprima: <assistantName> is listening...
    • Un método público status() que imprima: Voice Status: Active
  • main.cpp: Lee tres entradas (cada una en una línea separada):
    1. Nombre del dispositivo (string)
    2. Nombre de la red WiFi (string)
    3. Nombre del asistente de voz (string)

    Define una clase SmartSpeaker que herede públicamente tanto de WiFiDevice como de VoiceControl:

    • Un miembro privado std::string deviceName
    • Un constructor que reciba los tres parámetros, pase el nombre de la red a WiFiDevice y el nombre del asistente a VoiceControl utilizando la lista de inicialización, y almacene el nombre del dispositivo
    • Un método powerOn() que imprima: <deviceName> powering on..., luego llame a connect() y listen()
    • Un método showAllStatus() que imprima el nombre del dispositivo, luego use el operador de resolución de ámbito para llamar a ambos métodos status() para resolver la ambigüedad

    Crea un objeto SmartSpeaker con los valores de entrada. Llama a powerOn(), imprime una línea en blanco y luego llama a showAllStatus().

Por ejemplo, con las entradas Echo, HomeNetwork, y Alexa:

Echo powering on...
Connecting to WiFi: HomeNetwork
Alexa is listening...

Echo Status:
WiFi Status: Connected
Voice Status: Active

El método showAllStatus() debe imprimir el nombre del dispositivo seguido de " Status:" en una línea, luego llamar al método status() de cada clase base usando WiFiDevice::status() y VoiceControl::status() para evitar la ambigüedad, ya que ambas clases base tienen un método con el mismo nombre.

Hoja de referencia

C++ admite la herencia múltiple, lo que permite que una clase herede de múltiples clases base simultáneamente:

class DerivedClass : public BaseClass1, public BaseClass2 {
    // Class body
};

La clase derivada tiene acceso a los miembros de todas las clases base:

class Printer {
public:
    void print() {
        std::cout << "Printing document" << std::endl;
    }
};

class Scanner {
public:
    void scan() {
        std::cout << "Scanning document" << std::endl;
    }
};

class MultiFunctionDevice : public Printer, public Scanner {
public:
    void copy() {
        scan();   // From Scanner
        print();  // From Printer
    }
};

Los constructores de las clases base se llaman en el orden en que aparecen en la lista de herencia (de izquierda a derecha). Utilice la lista de inicialización para pasar argumentos a cada constructor base:

class MultiFunctionDevice : public Printer, public Scanner {
public:
    MultiFunctionDevice() : Printer(), Scanner() {}
};

Cuando varias clases base tienen miembros con el mismo nombre, utilice el operador de resolución de ámbito para resolver la ambigüedad:

class A { public: void show() {} };
class B { public: void show() {} };
class C : public A, public B {};

C obj;
obj.A::show();  // Call A's version
obj.B::show();  // Call B's version

Pruébalo tú mismo

#include <iostream>
#include <string>
#include "WiFiDevice.h"
#include "VoiceControl.h"

using namespace std;

// TODO: Definir la clase SmartSpeaker que herede públicamente tanto de WiFiDevice como de VoiceControl
// - Miembro privado: deviceName (string)
// - Constructor: toma deviceName, networkName, assistantName
//   Usar la lista de inicialización para pasar networkName a WiFiDevice y assistantName a VoiceControl
// - Método powerOn(): imprime "<deviceName> powering on...", luego llama a connect() y listen()
// - Método showAllStatus(): imprime "<deviceName> Status:", luego llama a ambos métodos status()
//   usando la resolución de ámbito (WiFiDevice::status() y VoiceControl::status())

class SmartSpeaker {
    // TODO: Implementar la clase SmartSpeaker aquí
};

int main() {
    string deviceName, networkName, assistantName;
    getline(cin, deviceName);
    getline(cin, networkName);
    getline(cin, assistantName);

    // TODO: Crear un objeto SmartSpeaker con los valores de entrada
    // TODO: Llamar a powerOn()
    // TODO: Imprimir una línea en blanco
    // TODO: Llamar a showAllStatus()

    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