Menu
Coddy logo textTech

Sobrescritura de métodos

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

Sobrescritura de métodos ocurre cuando una clase derivada proporciona su propia implementación de un método que ya existe en la clase base. Esto permite que las clases derivadas personalicen el comportamiento heredado manteniendo la misma firma del método.

Para sobrescribir un método, simplemente defina un método en la clase derivada con exactamente el mismo nombre, tipo de retorno y parámetros:

class Animal {
public:
    void speak() {
        std::cout << "Some sound" << std::endl;
    }
};

class Dog : public Animal {
public:
    void speak() {
        std::cout << "Woof!" << std::endl;
    }
};

Dog d;
d.speak();  // Salida: Woof!

La versión de la clase derivada oculta la versión de la clase base. Sin embargo, aún puedes acceder al método de la clase base utilizando el operador de resolución de ámbito:

class Dog : public Animal {
public:
    void speak() {
        Animal::speak();  // Llamar a la versión de la clase base
        std::cout << "Woof!" << std::endl;
    }
};

Existe una limitación importante con esta forma básica de sobrescritura. Cuando accedes a un objeto derivado a través de un puntero o referencia de la clase base, se llama a la versión de la clase base en su lugar:

Dog d;
Animal* ptr = &d;
ptr->speak();  // Salida: Some sound (not Woof!)

Esto sucede porque el compilador determina qué método llamar basándose en el tipo de puntero, no en el tipo de objeto real. Para lograr un polimorfismo de tiempo de ejecución real donde se llame al método correcto basándose en el objeto real, necesitarás funciones virtuales, las cuales cubriremos en la próxima lección.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de notificaciones que demuestre la sobrescritura de métodos en acción. Crearás una clase base Notifier y dos notificadores especializados que personalizan cómo se entregan los mensajes.

Organizarás tu código en tres archivos:

  • Notifier.h: Define una clase base Notifier con:
    • Un miembro protegido std::string recipient
    • Un constructor que recibe un nombre de destinatario y lo almacena
    • Un método público send(const std::string& message) que imprime: Sending to <recipient>: <message>
  • EmailNotifier.h: Define una clase EmailNotifier que hereda públicamente de Notifier:
    • Un constructor que recibe un destinatario y lo pasa a la clase base
    • Sobrescribe el método send() para llamar primero a la versión de la clase base usando Notifier::send(), y luego imprimir: [Email sent successfully]
  • main.cpp: Lee dos entradas (cada una en una línea separada):
    1. Nombre del destinatario (string)
    2. Contenido del mensaje (string)

    Define una clase SMSNotifier directamente en main.cpp que herede públicamente de Notifier:

    • Un constructor que recibe un destinatario y lo pasa a la clase base
    • Sobrescribe el método send() para imprimir: SMS to <recipient>: <message> (reemplazando completamente el comportamiento base sin llamarlo)

    Crea un objeto de cada tipo de notificador (base Notifier, EmailNotifier, y SMSNotifier) usando el mismo destinatario. Llama a send() en cada uno con el mensaje de entrada, imprimiendo una línea separadora entre cada uno:

    --- Base Notifier ---
    <output>
    --- Email Notifier ---
    <output>
    --- SMS Notifier ---
    <output>

Por ejemplo, con las entradas Alice y Hello there!:

--- Base Notifier ---
Sending to Alice: Hello there!
--- Email Notifier ---
Sending to Alice: Hello there!
[Email sent successfully]
--- SMS Notifier ---
SMS to Alice: Hello there!

Observa cómo EmailNotifier extiende el comportamiento base llamando primero al método del padre, mientras que SMSNotifier lo reemplaza completamente con su propia implementación. No olvides los protectores de encabezado (header guards) e incluir los encabezados apropiados en cada archivo.

Hoja de referencia

La sobrescritura de métodos (method overriding) permite que una clase derivada proporcione su propia implementación de un método de la clase base, manteniendo la misma firma del método (nombre, tipo de retorno y parámetros).

Sintaxis básica de la sobrescritura:

class Animal {
public:
    void speak() {
        std::cout << "Some sound" << std::endl;
    }
};

class Dog : public Animal {
public:
    void speak() {
        std::cout << "Woof!" << std::endl;
    }
};

Dog d;
d.speak();  // Output: Woof!

El método de la clase derivada oculta la versión de la clase base. Para llamar al método de la clase base desde la clase derivada, utilice el operador de resolución de ámbito:

class Dog : public Animal {
public:
    void speak() {
        Animal::speak();  // Call base class version
        std::cout << "Woof!" << std::endl;
    }
};

Limitación importante: Al acceder a un objeto derivado a través de un puntero o referencia de la clase base, se llama a la versión de la clase base:

Dog d;
Animal* ptr = &d;
ptr->speak();  // Output: Some sound (not Woof!)

Esto se debe a que el compilador determina qué método llamar basándose en el tipo de puntero, no en el tipo de objeto real. Para un polimorfismo de tiempo de ejecución real, utilice funciones virtuales.

Pruébalo tú mismo

#include <iostream>
#include <string>
#include "Notifier.h"
#include "EmailNotifier.h"

using namespace std;

// TODO: Define la clase SMSNotifier aquí que herede públicamente de Notifier
// - Constructor que pasa recipient a la clase base
// - Sobrescribe send() para imprimir: SMS to <recipient>: <message>
//   (reemplaza completamente el comportamiento base, no llames al send() del padre)

int main() {
    string recipient;
    string message;
    
    getline(cin, recipient);
    getline(cin, message);
    
    // TODO: Crea un objeto Notifier con recipient
    // Imprime "--- Base Notifier ---"
    // Llama a send() con message
    
    // TODO: Crea un objeto EmailNotifier con recipient
    // Imprime "--- Email Notifier ---"
    // Llama a send() con message
    
    // TODO: Crea un objeto SMSNotifier con recipient
    // Imprime "--- SMS Notifier ---"
    // Llama a send() con message
    
    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