Czy słowo kluczowe „zastąpienie” jest po prostu sprawdzeniem przesłoniętej metody wirtualnej?

226

O ile rozumiem, wprowadzenie overridesłowa kluczowego w C ++ 11 jest niczym innym jak tylko sprawdzeniem, czy zaimplementowana funkcja jest overrideing virtualfunkcji w klasie bazowej.

Czy to to?

aiao
źródło
50
Tak. ⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣
R. Martinho Fernandes,
13
Nie jest to jednak podwójna kontrola. To jedyny czek.
Nikos C.,
13
hej, zastąpienie NIE jest słowem kluczowym, to rodzaj gramatyki cukru. int override = 42; // OK
KAlO2
2
Dodatkowo poprawia czytelność, wyjaśniając, że zadeklarowana funkcja jest nadpisana;)
mots_g
5
Więc ... Kiedy C ++ 11 stanie się na tyle standardowy, że zaczną uczyć takich rzeczy na moim lokalnym 4-letnim rynku? Kiedy się dowiedzą ?!
Cinch

Odpowiedzi:

263

To rzeczywiście pomysł. Chodzi o to, że masz jasność co do tego, co masz na myśli, aby można było zdiagnozować cichy błąd:

struct Base
{
    virtual int foo() const;
};

struct Derived : Base
{
    virtual int foo()   // whoops!
    {
       // ...
    }
};

Powyższy kod się kompiluje, ale nie jest to, co mogłeś mieć na myśli (zwróć uwagę na brak const). Jeśli powiesz zamiast tego, virtual int foo() overrideotrzymasz błąd kompilatora, że ​​twoja funkcja w rzeczywistości niczego nie przesłania.

Kerrek SB
źródło
74
+1: Chociaż niestety jest to trochę czerwony śledź, gdy ludzie sugerują, że nowa overridefunkcja „naprawia” to; musisz pamiętać, aby z niego korzystać, tak jak powinieneś pamiętać, aby napisać const;)
Wyścigi lekkości na orbicie
Właśnie zdałem sobie sprawę, że explicitdefinicje klas nie dotarły do ​​C ++ 11. Huh
aschepler
1
@aschepler A co zrobiłaby explicitdefinicja klasy? Nigdy o tym nie słyszałem.
Christian Rau,
18
@LightnessRacesinOrbit: Tak, to nie jest głupi dowód; jednak pamiętanie ogólnej zasady (szaleńczego pisania, overridegdy ktoś zamierza to zrobić) jest bardziej prawdopodobne niż zapamiętywanie przypadków narożnych, tj. nie ma ogólności w kopiowaniu funkcji różnych prototypów, tylko nieprawidłowości, takie jak brak constlub pisanie charzamiast int, itp.
legends2k
1
@ Light, overridew tej odpowiedzi wspomniano najlepszy przypadek użycia specyfikatora , który jest bardziej futurystyczny niż natychmiastowy. Odpowiedź sugeruje, że zachować overridesię z virtualmetodą. W przyszłości, gdy ktoś omyłkowo zmieni podpis, zaczyna się jego przydatność.
iammilind 08.10.16
35

Cytat z Wikipedii:

Zastąpienie specjalnego identyfikatora oznacza, że ​​kompilator sprawdzi klasę (klasy) podstawową, aby sprawdzić, czy istnieje funkcja wirtualna z tą dokładną sygnaturą. A jeśli nie, kompilator wyłączy się.

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final

Edytuj (próbując nieco poprawić odpowiedź):

Zadeklarowanie metody jako „nadpisującej” oznacza, że ​​ta metoda ma na celu przepisanie (wirtualnej) metody w klasie bazowej. Metoda zastępująca musi mieć tę samą sygnaturę (przynajmniej dla parametrów wejściowych), co metoda, którą zamierza przepisać.

Dlaczego to jest konieczne? Cóż, zapobiega się następującym dwóm typowym przypadkom błędów:

  1. jeden błędnie wpisuje typ w nowej metodzie. Kompilator, nieświadomy, że zamierza napisać poprzednią metodę, po prostu dodaje ją do klasy jako nową metodę. Problem polega na tym, że stara metoda wciąż tam jest, nowa jest dodawana jako przeciążenie. W takim przypadku wszystkie wywołania starej metody będą działały tak jak poprzednio, bez żadnych zmian w zachowaniu (co byłoby celem samego przepisywania).

  2. zapomina się zadeklarować metodę w nadklasie jako „wirtualną”, ale nadal próbuje się zapisać ją w podklasie. Chociaż zostanie to najwyraźniej zaakceptowane, zachowanie nie będzie dokładnie zgodne z zamierzeniami: metoda nie jest wirtualna, więc dostęp przez wskaźniki w kierunku nadklasy zakończy wywoływanie starej metody (nadklasy) zamiast nowej metody (podklasy).

Dodanie „przesłonięcia” wyraźnie to jednoznacznie ukazuje: przez to mówi się kompilatorowi, że trzy rzeczy się spodziewają:

  1. istnieje metoda o tej samej nazwie w nadklasie
  2. ta metoda w nadklasie jest zadeklarowana jako „wirtualna” (tzn. przeznaczona do przepisania)
  3. metoda w nadklasie ma taki sam (wejściowy *) podpis jak metoda w podklasie (metoda przepisywania)

Jeśli którykolwiek z nich jest fałszywy, sygnalizowany jest błąd.

* Uwaga: parametr wyjściowy jest czasem innego, ale pokrewnego typu. Przeczytaj o przemianach kowariantnych i przeciwwariantowych, jeśli jesteś zainteresowany.

użytkownik1284631
źródło
31

Znalezione „ zastąpienie ” jest przydatne, gdy ktoś zaktualizował podpis metody wirtualnej klasy bazowej, taki jak dodanie opcjonalnego parametru, ale zapomniał zaktualizować podpis metody metody pochodnej. W takim przypadku metody między bazą a klasą pochodną nie są już relacjami polimorficznymi. Bez deklaracji zastąpienia trudno jest znaleźć tego rodzaju błąd.

użytkownik3792211
źródło
1
+1. Chociaż overridejest to świetny sposób na wykrycie takich problemów, dobry zasięg testów jednostkowych powinien również pomóc.
Rozczarowany
1
Właśnie dlatego jestem tak podekscytowany tym nowym specyfikatorem. Jedynym problemem jest to, że ta funkcja musi być już zastosowana, aby zapobiec błędom spowodowanym zmianami w klasach podstawowych. ;-)
Wilk
2

Wersja standardowa C ++ 17

Po przejrzeniu wszystkich overridetrafień w standardowej wersji roboczej C ++ 17 N4659 , jedyne odniesienie, które mogę znaleźć do overrideidentyfikatora, to:

5 Jeśli funkcja wirtualna jest oznaczona zastąpieniem specyfikatora virt i nie zastępuje funkcji składowej klasy podstawowej, program jest źle sformułowany. [Przykład:

struct B {
  virtual void f(int);
};

struct D : B {
  virtual void f(long) override; // error: wrong signature overriding B::f
  virtual void f(int) override;  // OK
}

- koniec przykładu]

więc myślę, że wysadzenie niewłaściwych programów to tak naprawdę jedyny efekt.

Ciro Santilli
źródło