Wie funktioniert die Operatorüberladung für << in iostream.h ?



  • Guten Tag,

    Wie kann man die Funktionsweise der Operatorüberladung für "<<" aus iostream.h nachzuvollziehen? Normalerweise kenne ich Operatorüberladung so:

    class Counter
     {
     public:
     Counter();
     ~Counter(){}
     int GetItsVal()const { return itsVal; }
     void SetItsVal(int x) {itsVal = x; }
     void Increment() { ++itsVal; }
     const Counter& operator++ ();
    
     private:
     int itsVal;
     };
    
     Counter::Counter():
     itsVal(0)
     {};
    
     const Counter& Counter::operator++()
     {
     ++itsVal;
     return *this;
     }
    

    In Zeile 9 wird der Operator ++ als Elementfunktion eingeführt und dann ab Zeile 19 definiert.

    Im Quellcode zu ostream wird der Operator << aber auf andere Art überladen, der Operator << steht nicht im Public-Bereich sondern wird definiert, ohne Elementfunktion zu sein.

    class ostream : public ios
    {
        void do_osfx();
      public:
        ostream();
        ostream(streambuf* sb, ostream* tied=NULL);
        ~ostream();
    
        int opfx() { if (!good()) return 0; if (_tie) _tie->flush(); return 1; }
        void osfx() { if (flags() & (ios::unitbuf|ios::stdio))
    		      do_osfx(); }
        streambuf* ostreambuf() const { return _strbuf; }
        ostream& flush();
        ostream& put(char c);
        ostream& write(const char *s, int n);
        ostream& write(const unsigned char *s, int n) { return write((char*)s, n);}
        ostream& write(const void *s, int n) { return write((char*)s, n);}
        ostream& seekp(streampos);
        ostream& seekp(streamoff, _seek_dir);
        streampos tellp();
        ostream& form(const char *format ...);
        ostream& vform(const char *format, _IO_VA_LIST args);
    };
    
    ostream& operator<<(ostream&, char c);
    ostream& operator<<(ostream& os, unsigned char c) { return os << (char)c; }
    

    Wie läuft es hier mit der Überladung? Danke für Antworten....



  • Du kannst Operatoren wahlweise als Member (linker Operand wird als *this, rechter als Parameter übergeben) oder als globale Funktion (beide Operanden werden als Parameter übergeben) überladen. In diesem Fall wurde letztere Variante gewählt.

    (für eigene Klassen mußt du deine IO-Operatoren übrigens auch als globale Funktionen überladen - weil DU die Klasse des linken Operanden nicht verändern darfst)



  • Aha! Danke.



  • Der operator<< ist in dem Fall eben nicht als Methode der Klasse deklariert sondern als freie "funktion", die einen operanden mehr nimmt als ein entsprechendes Klassenmember. Andersrum ausgedrueckt wuerde ein binaerer operator (wie +, -, =, << etc) als Klassenmember wie wenn man das Objekt selber als ertsen Operanden uebergibt. OPeratoren sind in C++ nichts anderes als Funktionen mit einer alternativen, speziellen Schreibweise.

    Beispiel:

    //Moeglichkeit a)
    class C;
    void foo(C& itsme, int i);
    C& operator<<(C& itsme, int i);
    
    //Moeglichkeit b)
    class C {
    public: 
      void foo(int i);
      C& operator<<(int i);
    }
    

    Wenn man jetzt etwas schreibt wie

    C c;
    c << 3;
    

    dann bedeutet das:

    //Moeglichkeit a)
    operator<<(c, 3);
    
    //Moeglichkeit b)
    c.operator<<(3);
    

    Die Schreibweise die man normalerweise kennt kann also entweder das eine oder das andere bedeuten, der User muss also nicht wissen wie rum es nun implementiert ist. Beide Arten sind fast aequivalent. Allerdings nur fast, weil bei der Version als Member das erste Argument nicht implizit konvertiert werden kann. Deshalb ist z.B. der operator+ fuer strings kein klassenmember, weil sonst Konstrukte wie

    string s = "Welt";
    string str = "Hallo " + s;
    

    nicht funktionieren wuerden: "Hallo: ist ein const char* und muss erst in einen string konvertiert weerden.

    /edit: mist, wieder romane getippst und CStoll war schneller...



  • pumuckl schrieb:

    /edit: mist, wieder romane getippst und CStoll war schneller...

    Dafür warst du ausführlicher 😃


Anmelden zum Antworten