Frage

Das ist im Grunde die Frage, gibt es eine „richtige“ Art und Weise operator<< zu implementieren? Lesen diese kann ich, dass so etwas wie sehen:

friend bool operator<<(obj const& lhs, obj const& rhs);

ist etwas bevorzugt wie

ostream& operator<<(obj const& rhs);

Aber ich kann nicht ganz verstehen, warum ich das eine oder andere verwenden soll.

Mein persönlicher Fall ist:

friend ostream & operator<<(ostream &os, const Paragraph& p) {
    return os << p.to_str();
}

Aber ich konnte wahrscheinlich tun:

ostream & operator<<(ostream &os) {
    return os << paragraph;
}

Welche Gründe sollte ich diese Entscheidung stützen auf?

Hinweis :

 Paragraph::to_str = (return paragraph) 

Dabei gilt Absatz ist eine Zeichenfolge.

War es hilfreich?

Lösung

Das Problem hier ist, in Ihrer Interpretation des Artikels Sie Link .

Dieser Artikel ist über jemanden, die Probleme richtig Definition der Bool Beziehung Operatoren haben.

Der Betreiber:

  • Gleichheit == und! =
  • Beziehung <> <=> =

Diese Operatoren sollten einen bool zurückgeben, da sie zwei Objekte des gleichen Typs vergleichen. Es ist in der Regel am einfachsten diese Operatoren als Teil der Klasse zu definieren. Dies liegt daran, eine Klasse automatisch ein Freund von selbst ist so Objekte vom Typ Paragraph einander untersuchen kann (auch jede andere private Mitglieder).

Es ist ein Argument für diese freistehenden Funktionen machen, da diese automatische Konvertierung beiden Seiten konvertieren kann, wenn sie nicht vom gleichen Typ sind, während Member-Funktionen nur die rhs erlauben Auto umgewandelt zu werden. Ich finde das ein Papier Mann Argument, wie Sie wirklich keine automatische Umwandlung geschieht in erster Linie (in der Regel) wollen. Aber wenn dies etwas, was Sie wollen (ich es nicht empfehlen), dann die Komparatoren kann freistehend machen vorteilhaft sein.

Der Strom Operatoren:

  • operator << Ausgabe
  • Operator >> Eingang

Wenn Sie diese als Strom Operatoren (und nicht als binäre Verschiebung) verwenden der erste Parameter ist ein Strom. Da Sie Zugriff auf den Stream-Objekt nicht (nicht zu ändern sein Ihr) haben diese nicht Mitglied Betreiber sein müssen sie die Klasse außerhalb sein. So müssen sie entweder Freunde der Klasse sein oder Zugang zu einem öffentlichen Verfahren, die das Streaming für Sie tun.

Es ist auch traditionell für diese Objekte einen Verweis auf ein Stream-Objekt zurück, so dass Sie Kette Stream-Operationen zusammen.

#include <iostream>

class Paragraph
{
    public:
        explicit Paragraph(std::string const& init)
            :m_para(init)
        {}

        std::string const&  to_str() const
        {
            return m_para;
        }

        bool operator==(Paragraph const& rhs) const
        {
            return m_para == rhs.m_para;
        }
        bool operator!=(Paragraph const& rhs) const
        {
            // Define != operator in terms of the == operator
            return !(this->operator==(rhs));
        }
        bool operator<(Paragraph const& rhs) const
        {
            return  m_para < rhs.m_para;
        }
    private:
        friend std::ostream & operator<<(std::ostream &os, const Paragraph& p);
        std::string     m_para;
};

std::ostream & operator<<(std::ostream &os, const Paragraph& p)
{
    return os << p.to_str();
}


int main()
{
    Paragraph   p("Plop");
    Paragraph   q(p);

    std::cout << p << std::endl << (p == q) << std::endl;
}

Andere Tipps

Sie können es als Mitglied Funktion nicht tun, weil die implizite this Parameter auf der linken Seite des <<-Operator ist. (Daher müßten Sie es als Member-Funktion in der ostream-Klasse hinzufügen Nicht gut:).

Könnten Sie es als freie Funktion tun, ohne es zu friending? Das ist, was ich bevorzuge, weil es deutlich macht, dass es sich um eine Integration mit ostream, und nicht um eine Kernfunktionalität der Klasse.

Wenn möglich, als Nicht-Mitglied und Nicht-friend-Funktionen.

Wie von Herb Sutter und Scott Meyers beschrieben, bevorzugen nicht-Freund Dritt Funktionen auf Member-Funktionen, um Verkapselung zu erhöhen.

In einigen Fällen wie C ++ Streams, werden Sie nicht die Wahl haben und müssen nicht-Member-Funktionen verwendet werden.

Aber noch, es bedeutet nicht, dass Sie diese Funktionen Freunde Ihrer Klassen machen: Diese Funktionen können noch Ihre Klasse durch Ihre Klasse Accessoren Acess. Wenn Sie in writting diese Funktionen auf diese Weise gelingt, dann hat man.

Über Operator << und >> Prototypen

Ich glaube, die Beispiele, die Sie in Ihrer Frage gab falsch sind. Zum Beispiel:

ostream & operator<<(ostream &os) {
    return os << paragraph;
}

Ich kann nicht einmal anfangen zu denken, wie diese Methode in einem Strom arbeiten könnte.

Hier sind die zwei Möglichkeiten, um die << und >> Betreiber zu implementieren.

Angenommen, Sie haben einen Strom-ähnliches Objekt vom Typ T verwendet werden soll.

Und das wollen Sie aus / in T die relevanten Daten des Objekts vom Typ Absatz extrahieren / eingefügt werden.

Allg Operator << und >> Funktionsprototypen

Die erste ist als Funktionen:

// T << Paragraph
T & operator << (T & p_oOutputStream, const Paragraph & p_oParagraph)
{
   // do the insertion of p_oParagraph
   return p_oOutputStream ;
}

// T >> Paragraph
T & operator >> (T & p_oInputStream, const Paragraph & p_oParagraph)
{
   // do the extraction of p_oParagraph
   return p_oInputStream ;
}

Allg Operator << und >> Methode Prototypen

Der zweite Wesen als Methoden:

// T << Paragraph
T & T::operator << (const Paragraph & p_oParagraph)
{
   // do the insertion of p_oParagraph
   return *this ;
}

// T >> Paragraph
T & T::operator >> (const Paragraph & p_oParagraph)
{
   // do the extraction of p_oParagraph
   return *this ;
}

Beachten Sie, dass diese Notation zu verwenden, müssen Sie T die Klassendeklaration verlängern. Für STL-Objekte, ist dies nicht möglich (Sie sollen nicht, sich ändern ...).

Und was ist, wenn T ein C ++ Stream ist?

Hier sind die Prototypen der gleichen << und >> Operatoren für C ++ Streams.

Für allgemeine basic_istream und basic_ostream

Beachten Sie, dass Fall des Stromes ist, wie Sie die C ++ Strom nicht ändern können, können Sie die Funktionen implementieren müssen. Was bedeutet, so etwas wie:

// OUTPUT << Paragraph
template <typename charT, typename traits>
std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & p_oOutputStream, const Paragraph & p_oParagraph)
{
   // do the insertion of p_oParagraph
   return p_oOutputStream ;
}

// INPUT >> Paragraph
template <typename charT, typename traits>
std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & p_oInputStream, const CMyObject & p_oParagraph)
{
   // do the extract of p_oParagraph
   return p_oInputStream ;
}

Für char istream und Ostream

Der folgende Code funktioniert nur für char-basierte Streams.

// OUTPUT << A
std::ostream & operator << (std::ostream & p_oOutputStream, const Paragraph & p_oParagraph)
{
   // do the insertion of p_oParagraph
   return p_oOutputStream ;
}

// INPUT >> A
std::istream & operator >> (std::istream & p_oInputStream, const Paragraph & p_oParagraph)
{
   // do the extract of p_oParagraph
   return p_oInputStream ;
}

Rhys Ulerich kommentierte über die Tatsache, die char-basierten Code ist nur eine „Spezialisierung“ des generischen Code darüber. Natürlich ist Rhys Recht: Ich habe nicht die Verwendung des char-basierten Beispiel empfehlen. Es ist hier nur gegeben, weil es einfacher zu lesen. Da es nur sinnvoll ist, wenn Sie nur mit char-basierten Streams arbeiten, sollen Sie es auf Plattformen vermeiden, in denen Wchar_t Code üblich ist (das heißt unter Windows).

Hope dies dazu beitragen wird.

Es sollte als freie, nicht-friend-Funktionen implementiert werden, vor allem wenn, wie die meisten Dinge in diesen Tagen, die Ausgabe hauptsächlich für Diagnose und Protokollierung verwendet wird. In konst Accessoren für all die Dinge, die in den Ausgang gehen müssen, und dann haben die Ausgeber nur diejenigen nennen und tun Formatierung.

ich tatsächlich genommen habe alle diese Ostream Ausgang frei Funktionen in einem „ostreamhelpers“ Header und Implementierungsdatei zu sammeln, es hält, dass sekundäre Funktionalität weit weg vom eigentlichen Zweck der Klassen.

Die Signatur:

bool operator<<(const obj&, const obj&);

Es scheint eher vermuten, dies nicht die stream Konvention paßt noch die bitweise Konvention, so dass es wie ein Fall von Betreibern Überlastung Missbrauch sieht, operator < sollte bool zurück, aber operator << soll wohl etwas anderes zurück.

Wenn Sie bedeuten, dass so sagen:

ostream& operator<<(ostream&, const obj&); 

Dann, da Sie können nicht Funktionen hinzufügen, indem Notwendigkeit ostream die Funktion eine freie Funktion sein muss, ob es sich um eine friend oder nicht, hängt davon ab, was es für den Zugriff hat (wenn es nicht privat oder geschützt Mitglieder zugreifen muss es gibt keine Notwendigkeit, es Freund).

Just for Vollendung willen, möchte ich hinzufügen, dass Sie in der Tat können erstellen einen Operator ostream& operator << (ostream& os) innerhalb einer Klasse und kann es funktionieren. Von dem, was ich weiß, es ist keine gute Idee, es zu benutzen, weil es sehr verworren ist und nicht intuitiv.

Nehmen wir an, wir haben diesen Code:

#include <iostream>
#include <string>

using namespace std;

struct Widget
{
    string name;

    Widget(string _name) : name(_name) {}

    ostream& operator << (ostream& os)
    {
        return os << name;
    }
};

int main()
{
    Widget w1("w1");
    Widget w2("w2");

    // These two won't work
    {
        // Error: operand types are std::ostream << std::ostream
        // cout << w1.operator<<(cout) << '\n';

        // Error: operand types are std::ostream << Widget
        // cout << w1 << '\n';
    }

    // However these two work
    {
        w1 << cout << '\n';

        // Call to w1.operator<<(cout) returns a reference to ostream&
        w2 << w1.operator<<(cout) << '\n';
    }

    return 0;
}

In Summe also bis - Sie können es tun, aber Sie wahrscheinlich nicht sollte:)

operator<< als Freund Funktion implementiert:

#include <iostream>
#include <string>
using namespace std;

class Samp
{
public:
    int ID;
    string strName; 
    friend std::ostream& operator<<(std::ostream &os, const Samp& obj);
};
 std::ostream& operator<<(std::ostream &os, const Samp& obj)
    {
        os << obj.ID<< “ ” << obj.strName;
        return os;
    }

int main()
{
   Samp obj, obj1;
    obj.ID = 100;
    obj.strName = "Hello";
    obj1=obj;
    cout << obj <<endl<< obj1;

} 
  

OUTPUT: 100 Hallo 100 Hallo Drücken Sie eine beliebige Taste, um fortzufahren ...

Dies kann ein Freund Funktion nur, weil das Objekt auf der rechten Seite von operator<< und Argument cout ist auf der linken Seite. Also das ist kein Mitglied Funktion der Klasse sein kann, kann es nur ein Freund Funktion sein.

Freund operator = gleiche Rechte wie Klasse

friend std::ostream& operator<<(std::ostream& os, const Object& object) {
    os << object._atribute1 << " " << object._atribute2 << " " << atribute._atribute3 << std::endl;
    return os;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top