Menu
Coddy logo textTech

Ridefinizione dei metodi

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 51 di 104.

L'override dei metodi si verifica quando una classe derivata fornisce una propria implementazione di un metodo già presente nella classe base. Questo permette alle classi derivate di personalizzare il comportamento ereditato mantenendo la stessa firma del metodo.

Per sovrascrivere un metodo, basta definire un metodo nella classe derivata con lo stesso identico nome, tipo restituito e parametri:

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();  // Risultato: Woof!

La versione della classe derivata nasconde quella della classe base. Tuttavia, puoi comunque accedere al metodo della classe base usando l'operatore di risoluzione dell'ambito:

class Dog : public Animal {
public:
    void speak() {
        Animal::speak();  // Chiama la versione della classe base
        std::cout << "Woof!" << std::endl;
    }
};

C'è una limitazione importante in questa forma di base dell'override. Quando accedi a un oggetto derivato tramite un puntatore o un riferimento alla classe base, viene chiamata la versione della classe base:

Dog d;
Animal* ptr = &d;
ptr->speak();  // Output: Un suono (non Woof!)

Questo accade perché il compilatore determina quale metodo chiamare in base al tipo del puntatore, non al tipo effettivo dell’oggetto. Per ottenere un vero polimorfismo a runtime, in cui il metodo corretto viene chiamato in base all’oggetto effettivo, ti serviranno le funzioni virtuali, che vedremo nella prossima lezione.

challenge icon

Sfida

Facile

Costruiamo un sistema di notifiche che mostri la sovrascrittura dei metodi in azione. Creerai una classe base Notifier e due notificatori specializzati che personalizzano il modo in cui vengono recapitati i messaggi.

Organizzerai il codice in tre file:

  • Notifier.h: definisci una classe base Notifier con:
    • Un membro protetto std::string recipient
    • Un costruttore che accetta il nome di un destinatario e lo memorizza
    • Un metodo pubblico send(const std::string& message) che stampa: Sending to <recipient>: <message>
  • EmailNotifier.h: definisci una classe EmailNotifier che eredita pubblicamente da Notifier:
    • Un costruttore che accetta un destinatario e lo passa alla classe base
    • Sovrascrivi il metodo send() in modo che chiami prima la versione della classe base usando Notifier::send(), quindi stampi: [Email sent successfully]
  • main.cpp: leggi due input (ciascuno su una riga separata):
    1. Nome del destinatario (stringa)
    2. Contenuto del messaggio (stringa)

    Definisci direttamente in main.cpp una classe SMSNotifier che eredita pubblicamente da Notifier:

    • Un costruttore che accetta un destinatario e lo passa alla classe base
    • Sovrascrivi il metodo send() in modo che stampi: SMS to <recipient>: <message> (sostituendo completamente il comportamento della classe base senza chiamarlo)

    Crea un oggetto per ciascun tipo di notificatore (base Notifier, EmailNotifier e SMSNotifier) usando lo stesso destinatario. Chiama send() su ciascuno con il messaggio di input e stampa una riga di separazione tra uno e l'altro:

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

Per esempio, con gli input 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!

Nota come EmailNotifier estenda il comportamento della classe base chiamando prima il metodo del genitore, mentre SMSNotifier lo sostituisca completamente con la propria implementazione. Non dimenticare le protezioni delle intestazioni e di includere le intestazioni appropriate in ciascun file.

Provalo tu

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

using namespace std;

// TODO: Definisci qui la classe SMSNotifier che eredita pubblicamente da Notifier
// - Costruttore che passa recipient alla classe base
// - Ridefinisci send() per stampare: SMS to &lt;recipient&gt;: &lt;message&gt;
//   (sostituisci completamente il comportamento della classe base, senza chiamare send() della classe genitore)

int main() {
    string recipient;
    string message;
    
    getline(cin, recipient);
    getline(cin, message);
    
    // TODO: Crea un oggetto Notifier con recipient
    // Stampa "--- Base Notifier ---"
    // Chiama send() con message
    
    // TODO: Crea un oggetto EmailNotifier con recipient
    // Stampa "--- Email Notifier ---"
    // Chiama send() con message
    
    // TODO: Crea un oggetto SMSNotifier con recipient
    // Stampa "--- SMS Notifier ---"
    // Chiama send() con message
    
    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C++ online