Menu
Coddy logo textTech

Überschreiben von Methoden

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 51 von 104.

Methodenüberschreibung tritt auf, wenn eine abgeleitete Klasse ihre eigene Implementierung einer Methode bereitstellt, die bereits in der Basisklasse existiert. Dies ermöglicht es abgeleiteten Klassen, geerbtes Verhalten anzupassen, während die gleiche Methodensignatur beibehalten wird.

Um eine Methode zu überschreiben, definieren Sie einfach eine Methode in der abgeleiteten Klasse mit genau demselben Namen, Rückgabetyp und denselben Parametern:

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

Die Version der abgeleiteten Klasse verdeckt die Version der Basisklasse. Sie können jedoch weiterhin über den Bereichsauflösungsoperator auf die Methode der Basisklasse zugreifen:

class Dog : public Animal {
public:
    void speak() {
        Animal::speak();  // Version der Basisklasse aufrufen
        std::cout << "Woof!" << std::endl;
    }
};

Es gibt eine wichtige Einschränkung bei dieser grundlegenden Form des Überschreibens. Wenn Sie über einen Basisklassen-Zeiger oder eine Referenz auf ein abgeleitetes Objekt zugreifen, wird stattdessen die Version der Basisklasse aufgerufen:

Dog d;
Animal* ptr = &d;
ptr->speak();  // Ausgabe: Ein Geräusch (nicht Wuff!)

Dies geschieht, weil der Compiler basierend auf dem Zeigertyp bestimmt, welche Methode aufgerufen werden soll, und nicht basierend auf dem tatsächlichen Objekttyp. Um echte Laufzeit-Polymorphie zu erreichen, bei der die richtige Methode basierend auf dem tatsächlichen Objekt aufgerufen wird, benötigen Sie virtuelle Funktionen, die wir in der nächsten Lektion behandeln werden.

challenge icon

Aufgabe

Einfach

Lass uns ein Benachrichtigungssystem erstellen, das das Überschreiben von Methoden in Aktion demonstriert. Du erstellst eine Notifier-Basisklasse und zwei spezialisierte Benachrichtigungsdienste, die anpassen, wie Nachrichten zugestellt werden.

Du organisierst deinen Code über drei Dateien:

  • Notifier.h: Definiere eine Notifier-Basisklasse mit:
    • Einem geschützten std::string recipient-Member
    • Einem Konstruktor, der einen Empfängernamen entgegennimmt und speichert
    • Einer öffentlichen send(const std::string& message)-Methode, die Folgendes ausgibt: Sending to <recipient>: <message>
  • EmailNotifier.h: Definiere eine EmailNotifier-Klasse, die öffentlich von Notifier erbt:
    • Einen Konstruktor, der einen Empfänger entgegennimmt und ihn an die Basisklasse weitergibt
    • Überschreibe die send()-Methode, sodass sie zuerst die Version der Basisklasse mit Notifier::send() aufruft und anschließend Folgendes ausgibt: [Email sent successfully]
  • main.cpp: Lies zwei Eingaben ein (jeweils in einer eigenen Zeile):
    1. Empfängername (String)
    2. Nachrichteninhalt (String)

    Definiere direkt in main.cpp eine SMSNotifier-Klasse, die öffentlich von Notifier erbt:

    • Einen Konstruktor, der einen Empfänger entgegennimmt und ihn an die Basisklasse weitergibt
    • Überschreibe die send()-Methode, sodass sie Folgendes ausgibt: SMS to <recipient>: <message> (das Verhalten der Basisklasse vollständig ersetzt, ohne sie aufzurufen)

    Erstelle jeweils ein Objekt jedes Benachrichtigungstyps (die Basis-Notifier-Klasse, EmailNotifier und SMSNotifier) unter Verwendung desselben Empfängers. Rufe bei jedem send() mit der eingegebenen Nachricht auf und gib zwischen den einzelnen Aufrufen eine Trennlinie aus:

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

Bei den Eingaben Alice und Hello there! sieht die Ausgabe beispielsweise so aus:

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

Beachte, wie EmailNotifier das Verhalten der Basisklasse erweitert, indem es zuerst die Elternmethode aufruft, während SMSNotifier sie vollständig durch seine eigene Implementierung ersetzt. Vergiss nicht die Header-Guards und die passenden Header in jede Datei einzubinden.

Probier es selbst

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

using namespace std;

// TODO: Definiere hier die Klasse SMSNotifier, die öffentlich von Notifier erbt
// - Konstruktor, der recipient an die Basisklasse übergibt
// - Überschreibe send(), um Folgendes auszugeben: SMS to <recipient>: <message>
//   (ersetze das Basisverhalten vollständig, rufe nicht die send() der Elternklasse auf)

int main() {
    string recipient;
    string message;
    
    getline(cin, recipient);
    getline(cin, message);
    
    // TODO: Erstelle ein Notifier-Objekt mit recipient
    // Gib "--- Base Notifier ---" aus
    // Rufe send() mit message auf
    
    // TODO: Erstelle ein EmailNotifier-Objekt mit recipient
    // Gib "--- Email Notifier ---" aus
    // Rufe send() mit message auf
    
    // TODO: Erstelle ein SMSNotifier-Objekt mit recipient
    // Gib "--- SMS Notifier ---" aus
    // Rufe send() mit message auf
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C++-Compiler