C++11 #7: Przeciążanie funkcji wirtualnych: specyfikator override.

Do każdego aspektu języka, z którego korzystamy, możemy mieć mniejsze lub większe uwagi. Oczywiście również posiadam swoją subiektywną listę niedociągnięć, jeśli chodzi o język C++.

Pomimo tego, że bardzo docieniam polimorfizm i sposób zaimplementowania tego mechanizmu, za niedopracowane uważam kwestie związane z dziedziczeniem i wykorzystaniem funkcji wirtualnych w C++.

Patrzę na takie rzeczy przez pryzmat problemów, które są niepotrzebnie generowane, utrudniając życie programistom. Jednym z moich faworytów jest brak mechanizmu, pozwalającego oznaczać metody wirtualne w klasach pochodnych jako przeciążone.

Problemy z przeciążaniem metod wirtualnych.

Spójrzmy na taką sytuację:

#include <iostream>

class ClassA
{
public:
    virtual ~ClassA() {}

    virtual void Function(int a_Argument)
    {
        std::cout << "ClassA::Function" << std::endl;
    }
};

class ClassB : public ClassA
{
public:
    virtual void Function(long a_Argument)
    {
        std::cout << "ClassB::Function" << std::endl;
    }
};

int main()
{
    ClassA* ptrA = new ClassB;
    ptrA->Function(4);
    
    delete ptrA;
    return 0;
}

Czy programista chciał przeciążyć funkcję Function z klasy bazowej ClassA ? Zapewne tak. Czy się udało ? Kod kompiluje się bez problemu, aplikacja również uruchamia się bez błędów. Natomiast na konsoli widzimy

ClassA::Function

zamiast

ClassB::Function

.

Powód ? Nagłówek funkcji Function w klasie pochodnej ma inny typ argumentu, niż wersja bazowa. Czasami bardzo trudno zauważyć takie błędy. Finalnie nie mamy przeciążenia funkcji wirtualnej w klasie pochodnej, a zwykłe przeładowanie nazwy funkcji z inną listą argumentów.

Wszystko jest super pod względem składni języka, ale nie o to nam chodziło…

Jeszcze łatwiejszym do przeoczenia błędem byłoby np. oznaczenie funkcji z klasy bazowej jako const. Dokładnie ta sama sytuacja – przeładowanie zamiast przeciążenia.

Specyfikator override.

Na szczęście definicja języka w wersji C++11 doczekała się zmian również pod tym względem. Jedną z nich jest nowy specyfikator (nie słowo kluczowe !) override. Umożliwia on oznaczenie funkcji w klasie pochodnej jako takiej, która powinna przeciążać funkcję wirtualną z klasy bazowej. Jeśli tak się nie dzieje, kompilator może zareagować odpowiednio do sytuacji.

Weźmy poprzedni przykład:

#include <iostream>

class ClassA
{
public:
    virtual ~ClassA() {}

    virtual void Function(int a_Argument)
    {
        std::cout << "ClassA::Function" << std::endl;
    }
};

class ClassB : public ClassA
{
public:
    virtual void Function(long a_Argument) override
    {
        std::cout << "ClassB::Function" << std::endl;
    }
};

int main()
{
    ClassA* ptrA = new ClassB;
    ptrA->Function(4);
    
    delete ptrA;
    return 0;
}

Kod różni się jedynie specyfikatorem override na końcu nagłówka funkcji Function w klasie pochodnej. Po tej zmianie kopilator krzyczy, że funkcja w klasie pochodnej niczego nie przeciąża – a powinna. Mamy więc jasny komunikat o błędzie w kodzie źródłowym.

Po wrowadzeniu niezbędnej poprawki (zmiana typu argumentu z long na int) i uruchomieniu aplikacji, na konsoli widzimy

ClassB::Function

, czyli wynik wg pierwotnego planu.

Podsumowanie.

Specyfikator override to doskonały krok w dobrym kierunku 🙂 Jest to jedna z ciekawszych nowości w C++11, która eliminuje cały zestaw potencjalnie paskudnych błędów, związanych z polimorfizmem.

Jedyne, na co można narzekać, to fakt, że override nie jest obowiązkowe podczas przeciążania funkcji wirtualnej. Powodem jest jednak najprawdopodobniej chęć zachowania kompatybilności wstecz ze starszym kodem, co jest nadal jednym z celów języka.

Kontynuuj poznawanie C++11: C++11 #8: Przeciążanie funkcji wirtualnych: specyfikator final.

2 komentarze do “C++11 #7: Przeciążanie funkcji wirtualnych: specyfikator override.”

  1. Dodatkową zaletą stosowania override jest zabezpieczenie przed usunięciem słowa virtual z klasy bazowej. W takiej sytuacji osoba, która chce to zrobić będzie świadoma, że są istnieją klasy pochodne. Dodatkowym smaczkiem, mniej znanym jest słowo kluczowe final, które także odnosi się do przeciążania metod.

    Odpowiedz

Dodaj komentarz