Menu
Coddy logo textTech

Nadpisywanie metod

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 51 z 104.

Przesłanianie metod występuje, gdy klasa pochodna dostarcza własną implementację metody, która już istnieje w klasie bazowej. Dzięki temu klasy pochodne mogą dostosowywać odziedziczone zachowanie, zachowując ten sam podpis metody.

Aby nadpisać metodę, po prostu zdefiniuj metodę w klasie pochodnej o dokładnie takiej samej nazwie, typie zwracanym i parametrach:

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

Wersja klasy pochodnej ukrywa wersję klasy bazowej. Nadal możesz jednak uzyskać dostęp do metody klasy bazowej za pomocą operatora rozstrzygania zakresu:

class Dog : public Animal {
public:
    void speak() {
        Animal::speak();  // Wywołaj wersję z klasy bazowej
        std::cout << "Woof!" << std::endl;
    }
};

Ta podstawowa forma przesłaniania ma istotne ograniczenie. Gdy uzyskujesz dostęp do obiektu klasy pochodnej za pomocą wskaźnika lub referencji do klasy bazowej, wywoływana jest wersja z klasy bazowej:

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

Dzieje się tak, ponieważ kompilator określa, którą metodę wywołać, na podstawie typu wskaźnika, a nie rzeczywistego typu obiektu. Aby uzyskać prawdziwy polimorfizm czasu wykonania, w którym wywoływana jest właściwa metoda na podstawie rzeczywistego obiektu, potrzebujesz funkcji wirtualnych, które omówimy na następnej lekcji.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system powiadomień, który pokazuje działanie przesłaniania metod. Utworzysz bazową klasę Notifier oraz dwa wyspecjalizowane powiadamiacze, które dostosowują sposób dostarczania wiadomości.

Rozmieścisz kod w trzech plikach:

  • Notifier.h: Zdefiniuj bazową klasę Notifier z:
    • Polem std::string recipient o dostępie chronionym
    • Konstruktorem, który przyjmuje nazwę odbiorcy i ją zapisuje
    • Publiczną metodą send(const std::string& message), która wyświetla: Sending to <recipient>: <message>
  • EmailNotifier.h: Zdefiniuj klasę EmailNotifier, która publicznie dziedziczy po Notifier:
    • Konstruktor, który przyjmuje odbiorcę i przekazuje go do klasy bazowej
    • Przesłoń metodę send(), aby najpierw wywołać wersję klasy bazowej za pomocą Notifier::send(), a następnie wyświetlić: [Email sent successfully]
  • main.cpp: Wczytaj dwa dane wejściowe (każde w osobnym wierszu):
    1. Nazwę odbiorcy (ciąg znaków)
    2. Treść wiadomości (ciąg znaków)

    Zdefiniuj klasę SMSNotifier bezpośrednio w main.cpp, która publicznie dziedziczy po Notifier:

    • Konstruktor, który przyjmuje odbiorcę i przekazuje go do klasy bazowej
    • Przesłoń metodę send(), aby wyświetlała: SMS to <recipient>: <message> (całkowicie zastępując zachowanie klasy bazowej bez jej wywoływania)

    Utwórz po jednym obiekcie każdego typu powiadamiacza (bazowego Notifier, EmailNotifier i SMSNotifier), używając tego samego odbiorcy. Wywołaj send() dla każdego z nich, przekazując wiadomość z danych wejściowych. Pomiędzy kolejnymi wywołaniami wyświetl linię separatora:

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

Na przykład dla danych wejściowych Alice i 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!

Zwróć uwagę, że EmailNotifier rozszerza zachowanie klasy bazowej, najpierw wywołując metodę klasy nadrzędnej, podczas gdy SMSNotifier całkowicie je zastępuje własną implementacją. Nie zapomnij o strażnikach nagłówków i dołączeniu odpowiednich nagłówków w każdym pliku.

Spróbuj swoich sił

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

using namespace std;

// TODO: Zdefiniuj tutaj klasę SMSNotifier, która publicznie dziedziczy po Notifier
// - Konstruktor, który przekazuje recipient do klasy bazowej
// - Nadpisz send(), aby wypisywała: SMS to <recipient>: <message>
//   (całkowicie zastąp zachowanie klasy bazowej, nie wywołuj send() klasy nadrzędnej)

int main() {
    string recipient;
    string message;
    
    getline(cin, recipient);
    getline(cin, message);
    
    // TODO: Utwórz obiekt Notifier z recipient
    // Wypisz "--- Base Notifier ---"
    // Wywołaj send() z message
    
    // TODO: Utwórz obiekt EmailNotifier z recipient
    // Wypisz "--- Email Notifier ---"
    // Wywołaj send() z message
    
    // TODO: Utwórz obiekt SMSNotifier z recipient
    // Wypisz "--- SMS Notifier ---"
    // Wywołaj send() z message
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online