Was ist der Vorteil, wenn eine private Methode in C ++ virtuell gemacht wird?
Ich habe dies in einem Open Source C ++ - Projekt bemerkt:
class HTMLDocument : public Document, public CachedResourceClient {
private:
virtual bool childAllowed(Node*);
virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&);
};
c++
polymorphism
access-specifier
Silverburgh
quelle
quelle
Antworten:
Herb Sutter hat es hier sehr schön erklärt .
Richtlinie 2: Machen Sie virtuelle Funktionen lieber privat.
Auf diese Weise können die abgeleiteten Klassen die Funktion überschreiben, um das Verhalten nach Bedarf anzupassen, ohne die virtuellen Funktionen direkt offen zu legen, indem sie von abgeleiteten Klassen aufgerufen werden (wie dies möglich wäre, wenn die Funktionen nur geschützt wären). Der Punkt ist, dass virtuelle Funktionen vorhanden sind, um die Anpassung zu ermöglichen. Sofern sie nicht auch direkt aus dem Code abgeleiteter Klassen aufgerufen werden müssen, müssen sie niemals etwas anderes als privat gemacht werden
quelle
Wenn die Methode virtuell ist, kann sie von abgeleiteten Klassen überschrieben werden, auch wenn sie privat ist. Wenn die virtuelle Methode aufgerufen wird, wird die überschriebene Version aufgerufen.
(Im Gegensatz zu Herb Sutter, der von Prasoon Saurav in seiner Antwort zitiert wurde, empfiehlt das C ++ FAQ Lite gegen private Virtuals , hauptsächlich weil es Menschen oft verwirrt.)
quelle
Trotz aller Aufrufe, ein virtuelles Mitglied für privat zu erklären, hält das Argument einfach kein Wasser. Häufig muss die Überschreibung einer virtuellen Funktion durch eine abgeleitete Klasse die Basisklassenversion aufrufen. Es kann nicht, wenn es deklariert ist
private
:Sie haben die Basisklassenmethode zu erklären
protected
.Dann müssen Sie das hässliche Mittel nehmen, über einen Kommentar anzuzeigen, dass die Methode überschrieben, aber nicht aufgerufen werden soll.
Also Herb Sutters Richtlinie Nr. 3 ... Aber das Pferd ist trotzdem aus dem Stall.
Wenn Sie etwas deklarieren, dem
protected
Sie implizit vertrauen, dass der Verfasser einer abgeleiteten Klasse die geschützten Interna versteht und ordnungsgemäß verwendet,friend
impliziert eine Deklaration ein tieferes Vertrauen für dieprivate
Mitglieder.Benutzer, die sich schlecht verhalten, wenn sie dieses Vertrauen verletzen (z. B. als "ahnungslos" bezeichnet, weil sie sich nicht die Mühe machen, Ihre Dokumentation zu lesen), sind selbst schuld.
Update : Ich habe einige Rückmeldungen erhalten, die besagen, dass Sie Implementierungen virtueller Funktionen auf diese Weise mithilfe privater virtueller Funktionen "verketten" können. Wenn ja, würde ich es gerne sehen.
Die von mir verwendeten C ++ - Compiler lassen eine abgeleitete Klassenimplementierung definitiv keine private Basisklassenimplementierung aufrufen.
Wenn das C ++ - Komitee "privat" lockern würde, um diesen spezifischen Zugriff zu ermöglichen, wäre ich alles für private virtuelle Funktionen. So wie es aussieht, wird uns immer noch geraten, das Scheunentor zu verschließen, nachdem das Pferd gestohlen wurde.
quelle
set_data
. Anweisungenm_data = ndata;
undcleanup();
könnte daher als Invariante betrachtet werden, die für alle Implementierungen gelten muss. Machen Sie deshalbcleanup()
nicht virtuell und privat. Fügen Sie einen Aufruf zu einer anderen privaten Methode hinzu, die virtuell und der Erweiterungspunkt Ihrer Klasse ist. Jetzt müssen Ihre abgeleiteten Klassen keine Basencleanup()
mehr aufrufen , Ihr Code bleibt sauber und Ihre Benutzeroberfläche ist schwer falsch zu verwenden.cleanup()
s in der Kette aufrufen müssen, fällt das Argument auseinander. Oder empfehlen Sie eine zusätzliche virtuelle Funktion für jeden Nachkommen in der Kette? Ick. Sogar Herb Sutter erlaubte geschützte virtuelle Funktionen als Lücke in seiner Richtlinie Nr. 3. Wie auch immer, ohne einen tatsächlichen Code wirst du mich nie überzeugen.Ich bin zum ersten Mal auf dieses Konzept gestoßen, als ich Scott Meyers '' Effective C ++ ', Punkt 35: Alternativen zu virtuellen Funktionen in Betracht gezogen habe. Ich wollte Scott Mayers für andere, die interessiert sein könnten, referenzieren.
Es ist Teil des Template-Methodenmusters über die nicht-virtuelle Schnittstellensprache : Die öffentlich zugänglichen Methoden sind nicht virtuell. Sie verpacken vielmehr die virtuellen Methodenaufrufe, die privat sind. Die Basisklasse kann dann vor und nach dem privaten virtuellen Funktionsaufruf Logik ausführen:
Ich denke, dass dies ein sehr interessantes Entwurfsmuster ist und ich bin sicher, dass Sie sehen können, wie nützlich das hinzugefügte Steuerelement ist.
private
? Der beste Grund ist, dass wir bereits einepublic
Verblendungsmethode bereitgestellt haben .protected
, dass ich die Methode für andere interessante Dinge verwenden kann? Ich nehme an, es wird immer von Ihrem Design abhängen und davon, wie Sie glauben, dass die Basisklasse passt. Ich würde argumentieren, dass sich der abgeleitete Klassenhersteller auf die Implementierung der erforderlichen Logik konzentrieren sollte. alles andere ist schon erledigt. Es geht auch um die Einkapselung.Aus C ++ - Sicht ist es völlig legitim, eine private virtuelle Methode zu überschreiben, obwohl Sie sie nicht aus Ihrer Klasse aufrufen können. Dies unterstützt das oben beschriebene Design.
quelle
Ich verwende sie, um abgeleiteten Klassen zu ermöglichen, die Lücken für eine Basisklasse zu füllen, ohne Endbenutzern eine solche Lücke aufzudecken. Zum Beispiel habe ich hochgradig statusbehaftete Objekte, die von einer gemeinsamen Basis abgeleitet sind und nur 2/3 der gesamten Zustandsmaschine implementieren können (die abgeleiteten Klassen stellen die verbleibenden 1/3 abhängig von einem Vorlagenargument bereit, und die Basis kann keine Vorlage für sein andere Gründe).
Ich MUSS die gemeinsame Basisklasse haben, damit viele der öffentlichen APIs korrekt funktionieren (ich verwende verschiedene Vorlagen), aber ich kann dieses Objekt nicht in die Wildnis lassen. Schlimmer noch, wenn ich die Krater in der Zustandsmaschine - in Form von reinen virtuellen Funktionen - irgendwo anders als in "Privat" belasse, erlaube ich einem klugen oder ahnungslosen Benutzer, der aus einer seiner untergeordneten Klassen stammt, Methoden zu überschreiben, die Benutzer niemals berühren sollten. Also habe ich das Gehirn der Zustandsmaschine in private PRIVATE Funktionen gesteckt. Dann füllen die unmittelbaren untergeordneten Elemente der Basisklasse die Lücken ihrer NICHT-virtuellen Überschreibungen aus, und Benutzer können die resultierenden Objekte sicher verwenden oder ihre eigenen weiteren abgeleiteten Klassen erstellen, ohne sich Gedanken über das Durcheinander der Zustandsmaschine machen zu müssen.
Was das Argument betrifft, dass Sie keine öffentlichen virtuellen Methoden haben sollten, sage ich BS. Benutzer können private Virtuals genauso einfach falsch überschreiben wie öffentliche - sie definieren schließlich neue Klassen. Wenn die Öffentlichkeit eine bestimmte API nicht ändern sollte, machen Sie sie in öffentlich zugänglichen Objekten überhaupt nicht virtuell.
quelle