Jaka jest zaleta uczynienia metody prywatnej wirtualną w C ++?
Zauważyłem to w projekcie C ++ open source:
class HTMLDocument : public Document, public CachedResourceClient {
private:
virtual bool childAllowed(Node*);
virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&);
};
c++
polymorphism
access-specifier
Silverburgh
źródło
źródło
Odpowiedzi:
Herb Sutter bardzo ładnie wyjaśnił to tutaj .
Wskazówka nr 2: wolę, aby funkcje wirtualne były prywatne.
Dzięki temu klasy pochodne zastępują funkcję w celu dostosowania zachowania w razie potrzeby, bez dalszego ujawniania funkcji wirtualnych bezpośrednio przez umożliwienie ich wywoływania przez klasy pochodne (co byłoby możliwe, gdyby funkcje były tylko chronione). Chodzi o to, że istnieją funkcje wirtualne, które umożliwiają dostosowywanie; jeśli nie trzeba ich również wywoływać bezpośrednio z kodu klas pochodnych, nie ma potrzeby, aby były one kiedykolwiek prywatne
źródło
Jeśli metoda jest wirtualna, może zostać zastąpiona przez klasy pochodne, nawet jeśli jest prywatna. Po wywołaniu metody wirtualnej zostanie wywołana zastąpiona wersja.
(W przeciwieństwie do Herba Suttera cytowanego przez Prasoon Saurav w jego odpowiedzi, C ++ FAQ Lite odradza prywatne wirtuale , głównie dlatego, że często dezorientuje ludzi.)
źródło
Pomimo wszystkich wezwań do ogłoszenia wirtualnego członka jako prywatnego, argument po prostu nie wytrzymuje. Często przesłonięcie funkcji wirtualnej przez klasę pochodną będzie musiało wywołać wersję klasy bazowej. Nie może, jeśli zostało zadeklarowane
private
:Ci mają zadeklarować metodę klasy bazowej
protected
.Następnie musisz zastosować brzydki cel wskazania za pomocą komentarza, że metoda powinna zostać zastąpiona, ale nie wywoływana.
Tak więc wskazówka Herba Suttera nr 3 ... Ale koń i tak wyszedł ze stajni.
Kiedy deklarujesz coś,
protected
co niejawnie ufasz autorowi dowolnej klasy pochodnej w zrozumieniu i prawidłowym używaniu chronionych elementów wewnętrznych, tak jakfriend
deklaracja sugeruje głębsze zaufanie dlaprivate
członków.Użytkownicy, którzy mają złe zachowanie z powodu naruszenia tego zaufania (np. Oznaczeni jako „nieświadomi”, nie zawracając sobie głowy czytaniem dokumentacji), mogą winić tylko siebie.
Aktualizacja : Otrzymałem opinię, która twierdzi, że można w ten sposób „łączyć” implementacje funkcji wirtualnych za pomocą prywatnych funkcji wirtualnych. Jeśli tak, z pewnością chciałbym to zobaczyć.
Kompilatory C ++, których używam, zdecydowanie nie pozwolą implementacji klasy pochodnej na wywołanie prywatnej implementacji klasy bazowej.
Gdyby komisja C ++ zwolniła „prywatne”, aby zezwolić na ten konkretny dostęp, byłbym całkowicie zwolennikiem prywatnych funkcji wirtualnych. W obecnym stanie nadal radzi się, abyśmy zamknęli drzwi do stodoły po kradzieży konia.
źródło
set_data
. Instrukcjem_data = ndata;
icleanup();
dlatego można je uznać za niezmiennik, który musi obowiązywać dla wszystkich implementacji. Dlatego uczyńcleanup()
niewirtualne i prywatne. Dodaj wywołanie do innej metody prywatnej, która jest wirtualna i stanowi punkt rozszerzenia Twojej klasy. Teraz nie ma już potrzeby, aby twoje klasy pochodne wywoływały podstawycleanup()
, twój kod pozostaje czysty, a interfejs jest trudny do nieprawidłowego użycia.cleanup()
s w łańcuchu, argument się rozpada. A może zalecasz dodatkową funkcję wirtualną dla każdego potomka w łańcuchu? Ick. Nawet Herb Sutter uznał chronione funkcje wirtualne jako lukę w swojej wytycznej nr 3. W każdym razie bez jakiegoś prawdziwego kodu nigdy mnie nie przekonasz.Po raz pierwszy natknąłem się na tę koncepcję, czytając „Efektywny C ++” Scotta Meyersa, punkt 35: Rozważ alternatywy dla funkcji wirtualnych.Chciałem polecić Scotta Mayersa innym, którzy mogą być zainteresowani.
Jest to część wzorca metody szablonu za pośrednictwem idiomu interfejsu nie-wirtualnego : publiczne metody nie są wirtualne; raczej opakowują wywołania metod wirtualnych, które są prywatne. Klasa bazowa może następnie uruchomić logikę przed i po wywołaniu prywatnej funkcji wirtualnej:
Myślę, że to bardzo ciekawy wzorzec projektowy i jestem pewien, że widać, jak przydatna jest dodatkowa kontrola.
private
? Najlepszym powodem jest to, że już udostępniliśmy plikpublic
metodę obliczania.protected
tak, żebym mógł użyć tej metody do innych interesujących rzeczy? Przypuszczam, że zawsze będzie to zależeć od twojego projektu i od tego, jak uważasz, że klasa bazowa pasuje. Twierdziłbym, że twórca klas pochodnych powinien skupić się na implementacji wymaganej logiki; wszystko inne jest już załatwione. Jest też kwestia hermetyzacji.Z punktu widzenia C ++, przesłonięcie prywatnej metody wirtualnej jest całkowicie uzasadnione, nawet jeśli nie będzie można jej wywołać ze swojej klasy. To wspiera projekt opisany powyżej.
źródło
Używam ich, aby umożliwić klasom pochodnym „wypełnienie luk” dla klasy bazowej bez ujawniania takiej dziury użytkownikom końcowym. Na przykład mam wysoce stanowe obiekty wywodzące się ze wspólnej bazy, która może zaimplementować tylko 2/3 ogólnej maszyny stanu (klasy pochodne zapewniają pozostałą 1/3 w zależności od argumentu szablonu, a podstawa nie może być szablonem dla inne powody).
POTRZEBUJĘ mieć wspólną klasę bazową, aby wiele publicznych interfejsów API działało poprawnie (używam różnorodnych szablonów), ale nie mogę wypuścić tego obiektu na wolność. Co gorsza, jeśli zostawię kratery w maszynie stanowej - w postaci czystych funkcji wirtualnych - gdziekolwiek poza "Prywatnym", pozwolę sprytnemu lub nieświadomemu użytkownikowi pochodzącemu z jednej z jego klas potomnych na przesłonięcie metod, których użytkownicy nigdy nie powinni dotykać. Dlatego umieściłem „mózgi” maszyny stanowej w PRYWATNYCH funkcjach wirtualnych. Następnie bezpośrednie elementy potomne klasy bazowej wypełniają puste miejsca w swoich NON-wirtualnych przesłonięciach, a użytkownicy mogą bezpiecznie używać wynikowych obiektów lub tworzyć własne dalsze klasy pochodne bez obawy o zepsucie maszyny stanowej.
Jeśli chodzi o argument, że nie powinieneś MIEĆ publicznych metod wirtualnych, mówię BS. Użytkownicy mogą w niewłaściwy sposób przesłonić prywatne wirtuale równie łatwo, jak publiczne - w końcu definiują nowe klasy. Jeśli publiczność nie powinna modyfikować danego API, nie czyń go W OGÓLE wirtualnym w publicznie dostępnych obiektach.
źródło