Menu
Coddy logo textTech

Sobrescrita de Métodos

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

Sobrescrita de método ocorre quando uma classe derivada fornece sua própria implementação de um método que já existe na classe base. Isso permite que as classes derivadas personalizem o comportamento herdado, mantendo a mesma assinatura de método.

Para sobrescrever um método, basta definir um método na classe derivada com exatamente o mesmo nome, tipo de retorno e 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();  // Saída: Woof!

A versão da classe derivada oculta a versão da classe base. No entanto, você ainda pode acessar o método da classe base usando o operador de resolução de escopo:

class Dog : public Animal {
public:
    void speak() {
        Animal::speak();  // Chama a versão da classe base
        std::cout << "Woof!" << std::endl;
    }
};

Existe uma limitação importante com esta forma básica de sobrescrita. Quando você acessa um objeto derivado através de um ponteiro ou referência da classe base, a versão da classe base é chamada em vez disso:

Dog d;
Animal* ptr = &d;
ptr->speak();  // Saída: Some sound (não Woof!)

Isso acontece porque o compilador determina qual método chamar com base no tipo do ponteiro, não no tipo real do objeto. Para alcançar o verdadeiro polimorfismo de tempo de execução, onde o método correto é chamado com base no objeto real, você precisará de funções virtuais, que abordaremos na próxima lição.

challenge icon

Desafio

Fácil

Vamos construir um sistema de notificação que demonstra a sobrescrita de métodos (method overriding) em ação. Você criará uma classe base Notifier e dois notificadores especializados que personalizam como as mensagens são entregues.

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

  • Notifier.h: Defina uma classe base Notifier com:
    • Um membro protegido std::string recipient
    • Um construtor que recebe o nome de um destinatário e o armazena
    • Um método público send(const std::string& message) que imprime: Sending to <recipient>: <message>
  • EmailNotifier.h: Defina uma classe EmailNotifier que herda publicamente de Notifier:
    • Um construtor que recebe um destinatário e o passa para a classe base
    • Sobrescreva o método send() para primeiro chamar a versão da classe base usando Notifier::send(), e depois imprimir: [Email sent successfully]
  • main.cpp: Leia duas entradas (cada uma em uma linha separada):
    1. Nome do destinatário (string)
    2. Conteúdo da mensagem (string)

    Defina uma classe SMSNotifier diretamente no main.cpp que herda publicamente de Notifier:

    • Um construtor que recebe um destinatário e o passa para a classe base
    • Sobrescreva o método send() para imprimir: SMS to <recipient>: <message> (substituindo completamente o comportamento base sem chamá-lo)

    Crie um objeto de cada tipo de notificador (base Notifier, EmailNotifier e SMSNotifier) usando o mesmo destinatário. Chame send() em cada um com a mensagem de entrada, imprimindo uma linha separadora entre cada um:

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

Por exemplo, com as entradas Alice e 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!

Observe como o EmailNotifier estende o comportamento base chamando o método pai primeiro, enquanto o SMSNotifier o substitui completamente por sua própria implementação. Não se esqueça dos header guards e de incluir os cabeçalhos apropriados em cada arquivo.

Folha de consulta

A sobrescrita de método (method overriding) permite que uma classe derivada forneça sua própria implementação de um método da classe base, mantendo a mesma assinatura do método (nome, tipo de retorno e parâmetros).

Sintaxe básica de sobrescrita:

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!

O método da classe derivada oculta a versão da classe base. Para chamar o método da classe base a partir da classe derivada, use o operador de resolução de escopo:

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

Limitação importante: Ao acessar um objeto derivado por meio de um ponteiro ou referência da classe base, a versão da classe base é chamada:

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

Isso ocorre porque o compilador determina qual método chamar com base no tipo do ponteiro, não no tipo real do objeto. Para um polimorfismo de tempo de execução real, use funções virtuais.

Experimente você mesmo

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

using namespace std;

// TODO: Defina a classe SMSNotifier aqui que herda publicamente de Notifier
// - Construtor que passa recipient para a classe base
// - Sobrescreva send() para imprimir: SMS to <recipient>: <message>
//   (substitua completamente o comportamento base, não chame o send() pai)

int main() {
    string recipient;
    string message;
    
    getline(cin, recipient);
    getline(cin, message);
    
    // TODO: Crie um objeto Notifier com recipient
    // Imprima "--- Base Notifier ---"
    // Chame send() com message
    
    // TODO: Crie um objeto EmailNotifier com recipient
    // Imprima "--- Email Notifier ---"
    // Chame send() com message
    
    // TODO: Crie um objeto SMSNotifier com recipient
    // Imprima "--- SMS Notifier ---"
    // Chame send() com message
    
    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