2013-05-24 21 views
7

W variousexplanations słowa kluczowego C++ 11: final, widzę przykłady takie jak to.Czy istnieje jakiś sens w oznaczaniu funkcji klasy podstawowej jako wirtualnej i końcowej?

class base 
{ 
public: 
    virtual void f() final; 
}; 

class derived : public base 
{ 
public: 
    virtual void f(); // Illegal due to base::f() declared final. 
}; 

Czy to jest rzeczywiście użyteczne użycie final? Dlaczego zadeklarowałbyś funkcję wirtualną w klasie bazowej (sugerując, że będzie ona użytecznie nadpisywalna w klasach pochodnych), a następnie natychmiast oznaczysz ją jako final (negując tę ​​implikację)? Jaka jest użyteczność virtual void f() final?

Widzę wartość oznaczającą derived::f() końcowy zamiast base::f(). W tym przypadku, base::f() prawdopodobnie miał dobry, oparty na wzornictwie, powód, dla którego f() powinien być wirtualny, a derived::f() osobno ma dobry, oparty na wzornictwie, powód, dla którego żadna inna klasa pochodna nie powinna unieważnić jego implementacji.

Jeśli nie chcesz, aby funkcja była zastępowana polimorficznie, dlaczego nie chcesz po prostu wyłączyć wirtualnego słowa kluczowego? Oczywiście klasy pochodne mogą nadal nadpisywać funkcję nie-polimorficznie. Czy celem klasy virtual void f() final w klasie bazowej jest zatem, aby w żaden sposób nie nadawać się do zmieniania - zarówno jako funkcja wirtualna, jak i nie-wirtualna? Jeśli tak, to wydaje się trochę niefortunne, że musimy dodać słowo kluczowe virtual w tym przypadku tylko, aby umożliwić korzystanie z final. Sądzę, że wtedy powinno być legalne oznaczanie funkcji nie-wirtualnych jako ostatecznych.

Dlaczego używać virtual void f() final dla funkcji wywodzącej się z klasy bazowej, gdy wydaje się, że poczucie virtual i poczucie final są sprzeczne?

+3

Przykładami są * przykłady *; mają na celu pokazać, co robi ta funkcja, niekoniecznie jak dokładnie z niej korzystać. W ten sposób używa się tylko dwóch klas, aby pokazać, co oznacza słowo "ostateczny". Aby użyć przykładu z prawdziwego świata, potrzebowalibyśmy * trzech *: jednego do zainicjowania wirtualnego, jednego do wyprowadzenia z niego i bycia "ostatecznym", a trzeciego do próby wyprowadzenia z niego i przeładowania go. Ta droga jest krótsza. –

+0

@NicolBolas Rozumiem cel przykładów. Ale czy ten konkretny przykład pokazuje również użyteczny paradygmat do zastosowania? Oto jest pytanie. – OldPeculier

Odpowiedz

4

Możesz oznaczyć go jako virtual, aby wskazać, że jest "wirtualny" w klasie, z której dziedziczysz (nawet jeśli nie musisz tego robić) i oznaczyć ją jako final, aby wskazać, że żadna klasa pochodząca z Twojej klasy może nadpisać to dalej. Może się tak zdarzyć, gdy na przykład implementujesz abstrakcyjną klasę podstawową. To jest C++ 11, więc nie jest użyteczne; override jest znacznie lepszym wskaźnikiem, ponieważ jest wymuszany przez kompilator.

Inna możliwość: chcesz, aby ta metoda nie została nadpisana, ale chcesz ją zmienić bez ponownej kompilacji. Pamiętaj, że virtual oznacza, że ​​znajduje się on w wirtualnej tabeli. nawet jeśli kompilator nie pozwoli ci go przesłonić.

Myślę, że celem przykładu, który pokazałeś, jest pokazanie priorytetów między virtual a końcowym i nic więcej. Jest to niezbyt użyteczny użytek.

Oznaczenie metody innej niż wirtualna jako final nie ma sensu, ponieważ i tak nie można jej przesłonić. Jeśli chcesz, aby kompilator zapobiegał ukrywaniu, jest to zupełnie inny problem, który nie ma nic wspólnego z metodą będącą final. W pewnym sensie metody nie-wirtualne są już ostateczne, ale ukryte.

+0

Oznaczenie funkcji jako 'wirtualnej' nie oznacza, że ​​jest' wirtualne' w bazie. Wskazuje, że jest on "wirtualny" w definiowanej klasie, niezależnie od tego, co może zrobić klasa podstawowa. –

+0

@Pete Becker: Myślę, że miał na myśli w zakresie tworzenia autodokumentowania kodu. Powszechną praktyką jest odnawianie wirtualnego słowa kluczowego podczas przeskakiwania bazy (szczególnie zanim C++ 11 dodał specyfikator przesłonięcia) tylko po to, aby programista odczytujący determinowaną definicję klasy wiedział, że konkretna metoda jest wirtualna. –

+0

@SeanMiddleditch - to oczywiście ** nie ** to, co powiedział. –

0

Alternatywa jest funkcją inną niż wirtualna. Ale funkcja inna niż wirtualna może być ukryta w klasie pochodnej. Więc jeśli chcesz zapobiec ukrywaniu się funkcji, możesz ją określić jako wirtualną ostatnią.

17

Czy istnieje jakiś sens w oznaczaniu funkcji klasy podstawowej jako wirtualnej i końcowej?

Tak, przynajmniej tymczasowo.

Znalazłem się w stosunkowo dużej i nieznanej istniejącej bazie kodu źródłowego C++. Znaczna część kodu została napisana przed C++ 11. Stwierdziłem, że chciałem upewnić się, że wszystkie przesłonięcia funkcji wirtualnej w klasie bazowej zostały oznaczone jako override. Najtrudniejszą częścią jest zlokalizowanie wszystkich tych nadpisań.

Oznaczyłem funkcję wirtualną w klasie bazowej na final, a kompilator szybko pokazał mi, gdzie zostało zadeklarowane każde nadpisanie. Wtedy było bardzo łatwo udekorować przesłonięcia, tak jak chciałem, i usunąć final z wirtualnego w klasie bazowej.

Powiązane problemy