Das ist im Grunde die Frage, gibt es einen "richtigen" Weg zur Implementierung operator<<
? Lesen Sie diese sehen , dass so etwas wie kann ich:
friend bool operator<<(obj const& lhs, obj const& rhs);
wird so etwas vorgezogen
ostream& operator<<(obj const& rhs);
Aber ich kann nicht genau verstehen, warum ich den einen oder anderen verwenden soll.
Mein persönlicher Fall ist:
friend ostream & operator<<(ostream &os, const Paragraph& p) {
return os << p.to_str();
}
Aber ich könnte wahrscheinlich tun:
ostream & operator<<(ostream &os) {
return os << paragraph;
}
Auf welche Gründe sollte ich diese Entscheidung stützen?
Hinweis :
Paragraph::to_str = (return paragraph)
Dabei ist Absatz eine Zeichenfolge.
c++
operator-overloading
Federico Builes
quelle
quelle
Antworten:
Das Problem liegt hier in Ihrer Interpretation des Artikels, den Sie verlinken .
Gleichberechtigung
Dieser Artikel handelt von jemandem, der Probleme hat, die Bool-Beziehungsoperatoren korrekt zu definieren.
Der Betreiber:
Diese Operatoren sollten einen Bool zurückgeben, wenn sie zwei Objekte desselben Typs vergleichen. Es ist normalerweise am einfachsten, diese Operatoren als Teil der Klasse zu definieren. Dies liegt daran, dass eine Klasse automatisch ein Freund von sich selbst ist, sodass Objekte vom Typ Paragraph sich gegenseitig untersuchen können (sogar die privaten Mitglieder des jeweils anderen).
Es gibt ein Argument für diese freistehenden Funktionen, da dadurch die automatische Konvertierung beider Seiten konvertiert werden kann, wenn sie nicht vom gleichen Typ sind, während Elementfunktionen nur die automatische Konvertierung der rhs ermöglichen. Ich finde das ein Argument von Paper Man, da Sie (normalerweise) nicht wirklich wollen, dass die automatische Konvertierung überhaupt stattfindet. Aber wenn Sie dies möchten (ich empfehle es nicht), kann es vorteilhaft sein, die Komparatoren freistehend zu machen.
Streaming
Die Stream-Betreiber:
Wenn Sie diese als Stream-Operatoren verwenden (anstatt als binäre Verschiebung), ist der erste Parameter ein Stream. Da Sie keinen Zugriff auf das Stream-Objekt haben (es kann nicht geändert werden), können diese keine Mitgliedsoperatoren sein. Sie müssen sich außerhalb der Klasse befinden. Daher müssen sie entweder Freunde der Klasse sein oder Zugriff auf eine öffentliche Methode haben, die das Streaming für Sie übernimmt.
Es ist auch üblich, dass diese Objekte einen Verweis auf ein Stream-Objekt zurückgeben, damit Sie Stream-Operationen miteinander verketten können.
quelle
operator<<
private:
?freiend
ist eine Möglichkeit, die öffentliche Schnittstelle zu erweitern, ohne die Kapselung zu unterbrechen. Lesen Sie programmers.stackexchange.com/a/99595/12917Sie können dies nicht als Elementfunktion ausführen , da sich der implizite
this
Parameter auf der linken Seite des<<
Operators befindet. (Daher müssten Sie es als Member-Funktion zurostream
-class hinzufügen. Nicht gut :)Könnten Sie es als freie Funktion tun, ohne
friend
es zu tun ? Das ist es, was ich bevorzuge, weil es klar macht, dass dies eine Integrationostream
und keine Kernfunktionalität Ihrer Klasse ist.quelle
friend
Funktion hat die gleichen Rechte als Mitglied - Funktion ( das ist , wasfriend
bedeutet), um einen Benutzer der Klasse möchte ich Wunder, warum es das brauchen würde. Dies ist die Unterscheidung, die ich mit der Formulierung "Kernfunktionalität" treffen möchte.Wenn möglich, als Nichtmitglied und Nichtfreund.
Wie von Herb Sutter und Scott Meyers beschrieben, bevorzugen Sie Funktionen von Nicht-Freunden, die keine Mitglieder sind, gegenüber Funktionen von Mitgliedern, um die Kapselung zu verbessern.
In einigen Fällen, wie bei C ++ - Streams, haben Sie keine Wahl und müssen Funktionen verwenden, die keine Mitglieder sind.
Dies bedeutet jedoch nicht, dass Sie diese Funktionen zu Freunden Ihrer Klassen machen müssen: Diese Funktionen können Ihre Klasse weiterhin über Ihre Klassenzugriffsberechtigten erreichen. Wenn es Ihnen gelingt, diese Funktionen auf diese Weise zu schreiben, haben Sie gewonnen.
Über Operator << und >> Prototypen
Ich glaube, die Beispiele, die Sie in Ihrer Frage gegeben haben, sind falsch. Beispielsweise;
Ich kann mir gar nicht vorstellen, wie diese Methode in einem Stream funktionieren könnte.
Hier sind die beiden Möglichkeiten, die Operatoren << und >> zu implementieren.
Angenommen, Sie möchten ein Stream-ähnliches Objekt vom Typ T verwenden.
Und dass Sie die relevanten Daten Ihres Objekts vom Typ Paragraph aus / in T extrahieren / einfügen möchten.
Generische Operator << und >> Funktionsprototypen
Das erste ist als Funktionen:
Generische Prototypen der Operatormethoden << und >>
Das zweite ist als Methoden:
Beachten Sie, dass Sie zur Verwendung dieser Notation die Klassendeklaration von T erweitern müssen. Für STL-Objekte ist dies nicht möglich (Sie sollten sie nicht ändern ...).
Und was ist, wenn T ein C ++ - Stream ist?
Hier sind die Prototypen derselben << und >> Operatoren für C ++ - Streams.
Für generischen basic_istream und basic_ostream
Beachten Sie, dass dies bei Streams der Fall ist, da Sie den C ++ - Stream nicht ändern können. Sie müssen die Funktionen implementieren. Was so etwas bedeutet wie:
Für char istream und ostream
Der folgende Code funktioniert nur für char-basierte Streams.
Rhys Ulerich kommentierte die Tatsache, dass der char-basierte Code nur eine "Spezialisierung" des darüber liegenden generischen Codes ist. Natürlich hat Rhys Recht: Ich empfehle die Verwendung des char-basierten Beispiels nicht. Es wird hier nur gegeben, weil es einfacher zu lesen ist. Da dies nur möglich ist, wenn Sie nur mit char-basierten Streams arbeiten, sollten Sie dies auf Plattformen vermeiden, auf denen wchar_t-Code häufig vorkommt (z. B. unter Windows).
Hoffe das wird helfen.
quelle
Es sollte als kostenlose, nicht befreundete Funktion implementiert werden, insbesondere wenn, wie die meisten Dinge heutzutage, die Ausgabe hauptsächlich für Diagnose und Protokollierung verwendet wird. Fügen Sie const-Accessoren für alle Dinge hinzu, die in die Ausgabe aufgenommen werden müssen, und lassen Sie den Outputter diese einfach aufrufen und formatieren.
Ich habe es mir zur Aufgabe gemacht, all diese ostream-ausgabefreien Funktionen in einem "ostreamhelpers" -Header und einer Implementierungsdatei zu sammeln. Dadurch wird diese sekundäre Funktionalität weit vom eigentlichen Zweck der Klassen entfernt.
quelle
Die Unterschrift:
Scheint eher verdächtig zu sein, dies passt weder zur
stream
Konvention noch zur bitweisen Konvention, so dass es so aussieht, als würde ein Missbrauch des Bedieners überladen,operator <
sollte zurückkehren , solltebool
aberoperator <<
wahrscheinlich etwas anderes zurückgeben.Wenn du es so gemeint hast, sag:
Da Sie dann nicht
ostream
unbedingt Funktionen hinzufügen können, muss die Funktion eine freie Funktion sein, ob sie eine istfriend
oder nicht, hängt davon ab, auf was sie zugreifen muss (wenn sie nicht auf private oder geschützte Mitglieder zugreifen muss, muss sie nicht erstellt werden Freund).quelle
ostream
dass bei Verwendung derostream.operator<<(obj&)
Bestellung ein Zugriff zum Ändern erforderlich ist . daher die freie Funktion. Andernfalls muss der Benutzertyp ein Dampftyp sein, um den Zugriff zu ermöglichen.Nur zur Vervollständigung möchte ich hinzufügen, dass Sie in der Tat einen Operator
ostream& operator << (ostream& os)
innerhalb einer Klasse erstellen können und dieser funktionieren kann. Soweit ich weiß, ist es keine gute Idee, es zu verwenden, da es sehr kompliziert und nicht intuitiv ist.Nehmen wir an, wir haben diesen Code:
Um es zusammenzufassen - Sie können es tun, aber Sie sollten es höchstwahrscheinlich nicht tun :)
quelle
Freund Operator = gleiche Rechte als Klasse
quelle
operator<<
als Freundfunktion implementiert:Dies kann nur eine Friend-Funktion sein, da sich das Objekt auf der rechten Seite
operator<<
und das Argumentcout
auf der linken Seite befindet. Dies kann also keine Mitgliedsfunktion der Klasse sein, sondern nur eine Freundfunktion.quelle