Menu
Coddy logo textTech

Redéfinition de méthodes

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 51 sur 104.

La redéfinition de méthode se produit lorsqu'une classe dérivée fournit sa propre implémentation d'une méthode qui existe déjà dans la classe de base. Cela permet aux classes dérivées de personnaliser le comportement hérité tout en conservant la même signature de méthode.

Pour redéfinir une méthode, définissez simplement une méthode dans la classe dérivée avec exactement le même nom, le même type de retour et les mêmes paramètres :

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

La version de la classe dérivée masque la version de la classe de base. Cependant, vous pouvez toujours accéder à la méthode de la classe de base en utilisant l'opérateur de résolution de portée :

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

Il existe une limitation importante avec cette forme de base de redéfinition (overriding). Lorsque vous accédez à un objet dérivé via un pointeur ou une référence de classe de base, c'est la version de la classe de base qui est appelée à la place :

Dog d;
Animal* ptr = &d;
ptr->speak();  // Résultat : Some sound (pas Woof !)

Cela se produit parce que le compilateur détermine quelle méthode appeler en se basant sur le type du pointeur, et non sur le type réel de l'objet. Pour parvenir à un véritable polymorphisme d'exécution où la méthode correcte est appelée en fonction de l'objet réel, vous aurez besoin de fonctions virtuelles, que nous aborderons dans la prochaine leçon.

challenge icon

Défi

Facile

Construisons un système de notification qui démontre la redéfinition de méthode (method overriding) en action. Vous allez créer une classe de base Notifier et deux notificateurs spécialisés qui personnalisent la manière dont les messages sont délivrés.

Vous organiserez votre code sur trois fichiers :

  • Notifier.h : Définissez une classe de base Notifier avec :
    • Un membre protégé std::string recipient
    • Un constructeur qui prend un nom de destinataire et le stocke
    • Une méthode publique send(const std::string& message) qui affiche : Sending to <recipient>: <message>
  • EmailNotifier.h : Définissez une classe EmailNotifier qui hérite publiquement de Notifier :
    • Un constructeur qui prend un destinataire et le transmet à la classe de base
    • Redéfinissez la méthode send() pour appeler d'abord la version de la classe de base en utilisant Notifier::send(), puis affichez : [Email sent successfully]
  • main.cpp : Lisez deux entrées (chacune sur une ligne séparée) :
    1. Le nom du destinataire (chaîne de caractères)
    2. Le contenu du message (chaîne de caractères)

    Définissez une classe SMSNotifier directement dans main.cpp qui hérite publiquement de Notifier :

    • Un constructeur qui prend un destinataire et le transmet à la classe de base
    • Redéfinissez la méthode send() pour afficher : SMS to <recipient>: <message> (en remplaçant complètement le comportement de base sans l'appeler)

    Créez un objet de chaque type de notificateur (base Notifier, EmailNotifier, et SMSNotifier) en utilisant le même destinataire. Appelez send() sur chacun avec le message d'entrée, en affichant une ligne de séparation entre chaque :

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

Par exemple, avec les entrées Alice et 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!

Remarquez comment EmailNotifier étend le comportement de base en appelant d'abord la méthode parente, tandis que SMSNotifier le remplace complètement par sa propre implémentation. N'oubliez pas les gardes d'inclusion (header guards) et d'inclure les en-têtes appropriés dans chaque fichier.

Aide-mémoire

La redéfinition de méthode (method overriding) permet à une classe dérivée de fournir sa propre implémentation d'une méthode de la classe de base, tout en conservant la même signature de méthode (nom, type de retour et paramètres).

Syntaxe de base de la redéfinition :

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!

La méthode de la classe dérivée masque la version de la classe de base. Pour appeler la méthode de la classe de base depuis la classe dérivée, utilisez l'opérateur de résolution de portée :

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

Limitation importante : Lors de l'accès à un objet dérivé via un pointeur ou une référence de la classe de base, c'est la version de la classe de base qui est appelée :

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

Ceci est dû au fait que le compilateur détermine quelle méthode appeler en fonction du type de pointeur, et non du type réel de l'objet. Pour un véritable polymorphisme au moment de l'exécution, utilisez des fonctions virtuelles.

Essayez vous-même

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

using namespace std;

// TODO: Définir la classe SMSNotifier ici qui hérite publiquement de Notifier
// - Constructeur qui passe recipient à la classe de base
// - Surcharger send() pour afficher : SMS to <recipient>: <message>
//   (remplacer complètement le comportement de base, ne pas appeler le send() parent)

int main() {
    string recipient;
    string message;
    
    getline(cin, recipient);
    getline(cin, message);
    
    // TODO: Créer un objet Notifier avec recipient
    // Afficher "--- Base Notifier ---"
    // Appeler send() avec message
    
    // TODO: Créer un objet EmailNotifier avec recipient
    // Afficher "--- Email Notifier ---"
    // Appeler send() avec message
    
    // TODO: Créer un objet SMSNotifier avec recipient
    // Afficher "--- SMS Notifier ---"
    // Appeler send() avec message
    
    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet