25

ich dies nur in einigen Code entdeckt:Warum sollte eine virtuelle Funktion privat sein?

class Foo { 
[...] 
private: 
    virtual void Bar() = 0; 
[...] 
} 

Hat das einen Zweck?

(I Port versuchen, einige Codes von VS bis G ++, und das meine Aufmerksamkeit erregt)

+1

Es tut mir leid, welcher Teil verwirrt Sie genau? – drxzcl

+20

Der "private" Teil. – liori

+8

Ich weiß nicht, ob Leute den vorherigen Kommentar aufheben, weil es komisch klingt oder weil sie auch verwirrt sind ... –

Antwort

23

this Herb Sutter article Siehe, warum Sie so etwas tun wollen würde

+8

besser paraphrasieren oder die Antwort in Ihren eigenen Worten zusammenfassen. verteilte Natur ftw. ;) – wilhelmtell

+8

Nein, besser nicht. Ich weiß nicht, wie Gregs pädagogische Fähigkeiten sind, aber ich bezweifle, dass sie besser sind als Sutters. –

+2

Also im Wesentlichen der Punkt hier ist das Template-Methode-Muster zu erzwingen? Damit die abgeleitete Klasse die Methode überschreiben kann, aber nur die Basisklasse kann sie jemals aufrufen? Ich denke, das ist nützlich, aber da die abgeleitete Klasse kann nur eine eigene interne Methode erstellen und diese von Bar() aufrufen, ich bin mir nicht sicher, ob das mehr als ein Vorschlag qualifiziert. – jprete

2

Es ist eine rein virtuelle Funktion ist. Jede endgültige Implementierung, die von "Foo" abgeleitet ist, muss die "Bar" -Funktion implementieren.

+0

, außer es ist als 'privat' markiert. Der OP machte seine Frage nicht klar, und ich musste es für ein oder zwei Sekunden betrachten, bevor ich erkannte, dass es als privat markiert war, also +1, um die -1 zu negieren. –

1

Es macht die Funktion rein virtuell im Gegensatz zu virtuellen.

Standardmäßig ist keine Implementierung vorgesehen, und die Absicht ist, dass die Funktionsimplementierung von einer erbenden Klasse angegeben werden muss. Dies kann jedoch überschrieben werden.

Manchmal werden vollständige Klassen angezeigt, in denen alle Elementfunktionen auf diese Weise als rein virtuell angegeben sind.

Dies sind abstrakte Basisklassen, manchmal als Interface-Klassen bezeichnet, und der Designer des ABC sagt Ihnen: "Ich habe jetzt eine Idee, wie diese Funktionalität für alle Spezialisierungen dieser Basisklasse implementiert werden würde. Aber Sie Alle müssen definiert sein, damit Ihre Spezialisierung funktioniert und Sie wissen, wie sich Ihr Objekt verhalten soll ".

Edit: Hoppla, habe gerade die Tatsache entdeckt, dass das Mitglied rein virtuelle Funktion ist privat. (Danke Michael) Das ändert die Dinge etwas.

Wenn diese Basisklasse mit privater Vererbung vererbt wird, ändert sich die Situation. Was der Designer der Basisklasse eigentlich macht, ist, dass, wenn Ihre abgeleitete Klasse eine nicht-private Funktion in der Basisklasse aufruft. Ein Teil des Verhaltens wurde an Ihre Spezialisierung der Funktion in Ihrer abgeleiteten Klasse delegiert. Das nicht private Mitglied macht "etwas" und ein Teil dieses "Etwas" ist ein Aufruf über die reine virtuelle Basisklassenfunktion zu Ihrer Implementierung.

Also einige öffentliche Funktion in Foo ruft die Bar-Funktion in Foo, und es beruht auf der Tatsache, dass Sie eine spezielle Implementierung der Bar-Funktion für Ihren speziellen Fall bereitstellen wird.

Scott Meyers bezeichnet dies als "umgesetzt in Bezug auf".

BTW Nur kichern über die Anzahl der Antworten, die schnell von Leuten gelöscht wurden, die auch das "Kleingedruckte" in der Frage nicht sahen! (-:.

HTH

prost,

0

Der einzige Zweck es zu dienen scheint, ist eine gemeinsame Schnittstelle zur Verfügung zu stellen

.

BTW obwohl eine Funktion als virtuelles private deklariert ist, kann es noch mit der Klasseninstanz oder von Freunden implementiert und aufgerufen werden.

Nichtsdestoweniger sollte diese Art von Dingen normalerweise als Schnittstelle dienen, aber ich tue es nicht so.

5

Ich werde eine kurze Erklärung von der großen C++ FAQ Lite zitieren, die es gut resümiert:

[23.4] Wann sollte jemand privat virtuals benutzen?

Fast nie.

Geschützte virtuelle sind in Ordnung, aber private virtuelle sind in der Regel ein Netto Verlust. Grund: private virtuelle verwechseln neue C++ - Programmierer, und Verwirrung erhöht Kosten, Verzögerungen Zeitplan und verringert Risiko.

Neue C++ - Programmierer werden durch private virtuals verwirrt, weil sie denken, dass eine private virtuelle nicht überschrieben werden kann. Schließlich kann eine abgeleitete Klasse nicht Mitglieder zugreifen, die in seiner Basisklasse privat sind, also, wie sie fragen, konnte es eine private virtuelle von seiner Basisklasse überschreiben? Es gibt Erklärungen für oben, aber das ist akademisch. Das echte Problem ist, dass fast jeder verwirrt wird, wenn sie zum ersten Mal in private virtuals laufen lassen, und Verwirrung ist schlecht.

Wenn es keinen zwingenden Grund gibt, das Gegenteil, vermeiden Sie private virtuals.


Die C++ FAQ Lite in der Zwischenzeit wurde aktualisiert:

By the way, es verwirrt die meisten Anfänger C++ Programmierer, dass private virtuals außer Kraft gesetzt werden können, geschweige denn überhaupt gültig. Wir alle wurden gelehrt, dass private Mitglieder in einer Basisklasse in davon abgeleiteten Klassen nicht zugänglich sind, was korrekt ist. Diese Unzugänglichkeit durch die abgeleitete Klasse hat jedoch nichts mit dem Mechanismus des virtuellen Aufrufs zu tun, der mit der abgeleiteten Klasse zusammenhängt. Da dies Anfänger verwirren könnte, die C++ - FAQ früher empfohlen, die Verwendung von geschützten virtuals anstatt private virtuals. Allerdings ist der private virtuelle Ansatz nun so weit verbreitet, dass eine Verwirrung der Anfänger weniger Anlass zur Sorge gibt.

+2

Ich denke, dass Cline und Sutter hier nicht übereinstimmen. Siehe den Link in Greg Rogers 'Antwort. –

+5

Deshalb mag ich die C++ - FAQ nicht, die voller Meinungen sind, die manchmal einfach albern sind, und gegen die Best Practices geht, wie sie von einigen der führenden Denker auf diesem Gebiet definiert wurden. Siehe Herb Sutters Antwort für eine viel bessere Erklärung, die die opische Meinung hat. –

+0

Die Standard-Stream-Bibliothek ist auch ein großartiger Ort, um Beispiele für private virtuelle Funktionen mit öffentlichen nicht virutal zu sehen, die sie verwenden. –

5

Die übliche "akademische" Antwort lautet: Zugriffsspezifizierer und Virtualität sind orthogonal - das eine beeinflusst nicht das andere.

Eine etwas praktischere Antwort: private virtuelle Funktionen werden häufig verwendet, um das Entwurfsmuster Template Method zu implementieren. In Sprachen, die keine privaten virtuellen Funktionen unterstützen, muss die Vorlagenmethode öffentlich sein, obwohl sie eigentlich nicht Teil der Benutzeroberfläche sein soll.

+0

Wenn Zugriffsspezifizierer und Virtualität orthogonal sind, warum http://ideone.com/JjbVOP bei der Kompilierung fehlschlägt? Virtuelle Funktionsaufruf wird zur Laufzeit nicht zur Kompilierzeit gelöst dann was habe ich in meinem Programm falsch gemacht? Ist es nicht möglich, geschützte virtuelle Methoden der Basisklasse durch die abgeleitete Klasse zu überschreiben? – Destructor

+0

@Destruktor Dieser Kompilierungsfehler liegt daran, dass Sie versuchen, eine geschützte Methode von 'Parent' von' main() 'aufzurufen. –

10

Dies ist eine rein virtuelle Funktion, die zufällig privat ist. Dies macht es so, dass eine abgeleitete Klasse die Methode implementieren muss. In diesem Fall Bar.

Ich denke, dass Sie verwirrt sein können b/c Dies wird getan, um "Schnittstellen" in C++ zu erstellen, und viele Leute denken an diese als öffentlich. Es gibt Fälle, in denen Sie eine private Schnittstelle definieren möchten, wenn eine öffentliche Methode diese privaten Methoden verwendet, um die Reihenfolge ihres Aufrufs sicherzustellen.(Ich glaube, das die Template-Methode genannt wird)

Für ein relativ schlechtes Beispiel :)

 
class RecordFile 
{ 
    public: 
     RecordFile(const std::string &filename); 

     void process(const Record &rec) 
     { 
      // Call the derived class function to filter out 
      // records the derived instance of this class does 
      // not care about 
      if (filterRecord(rec))  
      { 
       writeRecordToFile(rec);   
      } 
     }; 

    private: 
     // Returns true if the record is of importance 
     // and should be kept 
     virtual bool filterRecord(const Record &rec) = 0; 

     void writeRecordToFile(const Record &rec); 
}; 

+2

Ich verstehe es nicht, weil private Methoden in abgeleiteten Klassen nicht sichtbar sind. Wie kann eine abgeleitete Klasse eine Methode außer Kraft setzen, die sie nicht "sehen" oder aufrufen oder in irgendeiner Weise darauf zugreifen kann? – abelenky

+0

+1 - Sie haben praktische Argumente für Herb Sutters Argumentation gegeben. –

+17

Abelenky, Sie haben die primäre Quelle der Verwirrung in Bezug auf private virtuals aufgezeigt, aber Tatsache ist, dass Sie nicht in der Lage sein müssen * eine * Funktion * aufzurufen, um * sie * definieren zu können. Auf diese Weise kann die Basisklasse ihren Nachkommen sagen: "Stellen Sie mir eine Funktion zur Verfügung, aber ich allein sollte entscheiden, wann ich sie aufrufen soll." –

9

ISO C++ 2003 erlaubt es ausdrücklich:

§10.3 Staaten nichts über Zugriffsbezeichner und enthält sogar eine Fußnote in der zweiten Klausel im Zusammenhang mit der virtuellen Funktion Angabe überschreibt:

[...] Zutrittskontrolle (Ziffer 11) ist in nicht berücksichtigte 0 Bestimmungüberschreiben.

Der Code ist vollständig legal.

Verwandte Themen