Funkcje wirtualne istniały w C++ od początku jako środek dynamicznego polimorfizmu. Jednak wcześniej nie istniał mechanizm składniowy, który zmuszałby kompilator do sprawdzania poprawności przesłaniania wirtualnych funkcji w klasach pochodnych. Po wprowadzeniu C++11 słowo kluczowe override stało się narzędziem dodatkowej weryfikacji przez kompilator.
Bez override kompilator nie gwarantuje, że funkcja rzeczywiście przesłania metodę klasy bazowej. Błędy w sygnaturze (na przykład, niewłaściwy typ lub const) prowadzą do utworzenia nowej funkcji w klasie pochodnej („przesłonięcia”), co łamie polimorfizm i utrudnia debugowanie.
Użycie override przy deklaracji wirtualnej funkcji w klasie pochodnej pozwala kompilatorowi sprawdzić, czy sygnatura dokładnie odpowiada wirtualnej funkcji rodzica i że funkcja rzeczywiście przesłania rodzica. W przeciwnym razie kompilacja zostaje przerwana z błędem.
Przykład kodu:
struct Base { virtual void foo() const {} }; struct Derived : Base { void foo() const override { /* implementacja */ } };
Jeśli w Derived napiszemy void foo() bez const override, kompilator zgłosi błąd.
Kluczowe cechy:
Czy można zostawić wirtualną funkcję ze słowem kluczowym 'override', ale bez słowa kluczowego 'virtual'?
Tak, override implikuje, że funkcja jest wirtualna. Określenie virtual razem z override jest nadmiarowe, ale nie jest zabronione.
Czy możliwy jest błąd, jeśli funkcja różni się tylko modyfikatorem const lub ref qualifier (np. & lub &&)?
Tak, wszelkie różnice w sygnaturze, w tym według const/referencji, łamią przesłanianie. Na przykład, void foo() override nie przesłania void foo() const, a kompilator dzięki override to wychwyci.
Czy można stosować 'override' do funkcji statycznych lub konstruktorów?
Nie. override jest tylko dla funkcji wirtualnych, nie można go stosować do funkcji statycznych, konstruktorów, destruktorów (jeśli nie są wirtualne).
W dużym projekcie klasa pochodna ma literówkę w sygnaturze funkcji: funkcja w rzeczywistości nie jest override, ale programista uważa inaczej, polimorfizm nie działa zgodnie z oczekiwaniami.
Zalety:
Wady:
We wszystkich klasach pochodnych używana jest override, testy łapią błędy już na etapie kompilacji.
Zalety:
Wady: