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ę:

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

zamiast

.

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:

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

, 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.