2017-09-27 19 views
41

Na przykład:Czy jest jakiś sens używania `override` podczas przesłonięcia czystej funkcji wirtualnej?

class Base { 
    virtual void my_function() = 0; 
}; 

class Derived : Base { 
    void my_function() override; 
}; 

Z tego co czytałem, słowo override stosowany jest, aby upewnić się, że mamy prawidłowy podpis do funkcji, które są nadrzędne, a wydaje się, że jego jedyne zastosowanie.

Jednak w przypadku czystej funkcji wirtualnej kompilator zgłosiłby błąd, jeśli użylibyśmy niepoprawnej sygnatury w klasie pochodnej (lub klasie bazowej, w zależności od tego, jak widzimy rzeczy). Czy jest jakiś sens dodania override na końcu deklaracji ?

+4

Należy pamiętać, że abstrakcyjność * propaguje *. Jeśli podasz błędną sygnaturę w klasie "Pochodna", wówczas klasa "Pochodna" również staje się abstrakcyjna. To może nie zostać wykryte we właściwym miejscu bez słowa kluczowego 'override'. –

+4

Zapewnia to, że jeśli klasa podstawowa zmieni się w sposób niekompatybilny z asercją 'override', twój kod się nie skompiluje. – EJP

+1

"Pingowanie celowo programów pedagogicznych propaguje preferowane praktyki programistyczne" - T.J.Elgan – coderatchet

Odpowiedz

67

However, in the case of a pure virtual function, the compiler would throw an error if we used an incorrect signature in the Derived class

Nie, to kompiluje:

class Base { 
    virtual void my_function() = 0; 
}; 

class Derived : Base { 
    void my_function(int); 
//     ^^^ mistake! 
}; 

Chociaż nie:

class Base { 
    virtual void my_function() = 0; 
}; 

class Derived : Base { 
    void my_function(int) override; 
}; 

error: void Derived::my_function(int) marked override , but does not override


Błąd mówisz tylko wtedy, gdy instancji Derived - override pozwala y ou złapać błąd wcześniej i sprawia, że ​​definicja Derived jest bardziej przejrzysta/bardziej czytelna.

+0

Możesz dodać błąd runtime z inną klasą i zaimplementować 'Base :: my_function' pozostawiając go czystym wirtualnym. – Yakk

+3

czekaj, więc jest jakiś punkt? Dalej mówisz o tym, jak to jest przydatne, ale zacznij od "nie". – snb

+10

"Nie" jest odpowiedzią na twierdzenie, że kompilator zgłasza błąd. –

30

Tak, dobrze jest używać słowa kluczowego override konsekwentnie jako praktyki defensywnej.

Należy rozważyć przeprojektowanie, gdy autor Base zdecyduje, że my_function nie powinien być już czystym wirtualnym, a także, że powinien przyjąć nowy parametr. Po zainstalowaniu override kompilator złapie ten problem; bez klasy override, twoja klasa Derived będzie kontynuować kompilację.

7

Tak !!

To poprawia czytelność kodu: override kluczowe zapobiega dwuznaczności i przekazać to znaczenie nadrzędne swoją metodę klasy bazowej.

Zapobiega potencjalnym niezamierzone użycie: W przyszłości, jeśli podpis metoda zmiany klasy bazowej (tutaj virtual), to zmusić czerpać klasę odpowiednio zmienić. (z błędem kompilatora). W przeciwnym razie (bez słowa kluczowego override) można go uznać za method overload, co nie jest zamierzone.

+0

nie byłoby przeciążeniem metody z powodu normalnego ukrywania się – RiaD

3

Zwykle nie przejmuj się z override po prostu przesyła błąd. Znajduję lokalizację, w której błąd jest lepszy - w miejscu, w którym definiujesz metodę, której nie można przesłonić, zamiast tworzyć instancję klasy.

Ale istnieje sposób, aby to chronić przed błędem uruchomieniowym.

struct Base { 
    virtual void foo(int x = 0) = 0; 

    void foo(double d) { 
     foo((int)d); 
    } 
}; 
inline void Base::foo(int x) { std::cout << "Default foo(" << x << ")\n"; } 

struct Derived:Base { 
    using Base::foo; 
    virtual void foo() { // oops, no int! 
    std::cout << "Derived::foo()\n"; 
    Base::foo(); 
    } 
}; 
struct Derived2:Derived { 
    virtual void foo(int x=0) override { 
    std::cout << "Derived2::foo()\n"; 
    Derived::foo(x); 
    } 
}; 

tutaj zamierzamy dla każdego foo zadzwonić jego rodzica foo.Ale ponieważ Derived::foo nie zastępuje tego samego podpisu co Base::foo, nie jest wywoływany.

Dodaj override po foo() w Derived i otrzymamy błąd czasu kompilacji.

I tak, zaimplementowałem czystą funkcję wirtualną Base::foo.

Powiązane problemy