'<<' operator überladen



  • Hallo Leute

    ich hab mir hier eine Klasse (nur zur Übung zum thema OOP) geschrieben und will den Ausgabe '<<' operator überladen

    problem ist nur dass visual c++ 2008 debkt dass ich den binären '<<' operator meine und mir deshalb ohne ende fehler anzeigt:

    // Array.h
    #include <iostream>
    #include <ostream>
    
    using namespace std;
    
    class Array
    {
    public:
        // zeugs
        ostream& operator << (ostream& stream, Array const& obj)
        {
              obj.ausgeben(stream);
    	  return stream;
        }
    
        void ausgeben(ostream& stream) const;
        // zeugs
    };
    
    // Array.cpp
    #include "Array.h"
    #include <iostream>
    #include <ostream>
    
    void Array::ausgeben(std::ostream& stream) const
    {
    	for(UINT i = 0; i < length; ++i )
    	{
    		if ( i%3 == 0 )
    			stream<<std::endl;
    		stream<<value[i];
    	}
    	stream<<std::endl;
    }
    
    // Main.cpp
    
    int main()
    {
         Array c(/* Ctor Parameter */)
         c.ausgeben(cout);                  // klappt
         cout<< c;                          // klappt nicht
    
         system("PAUSE");
         return 0;
    }
    
    error C2804: Binärer Operator '<<' hat zu viele Parameter
    error C2333: 'Array::operator <<': Fehler in Funktionsdeklaration; Funktionstext wird übersprungen
    error C2804: Binärer Operator '<<' hat zu viele Parameter
    error C2333: 'Array::operator <<': Fehler in Funktionsdeklaration; Funktionstext wird übersprungen
    

    das sind die fehler (mich wunderts nur warum die doppelt ausgegeben werden????)

    naja es klappt halt nicht

    gruss Skym0sh0³



  • Du musst den << Operator global überladen, dass heisst, er darf nicht Member Deiner Klasse sein.
    Also als Friend deklarieren und dann global überladen.



  • also in diesem tutorial steht dass es auch so geht, und ich ja genau das gemacht, oder etwa nicht?



  • Skym0sh0 schrieb:

    also in diesem tutorial steht dass es auch so geht, und ich ja genau das gemacht, oder etwa nicht?

    Nein.



  • Nein, der operator<< in dem Tutorial gehört nicht zur Klasse für die er überladen wird. Guck es Dir mal genau an.
    Dein überladener operator<< ist hingegen ein Member Deiner Array-Klasse.



  • ah shit stimmt

    jetzt seh ichs 😡

    danke

    aber ist es nicht übersichtlicher und sinnvoller den nur in der klasse zu überladen
    sprich so wie ichs eigendlich vorhatte?

    und noch schnell ne frage:

    wenn ich hier

    std::cout<< c;
    

    statt

    cout
    

    eifnach folgendes schreibe:

    #include <fstream>
    using namespace std;
    
    int main()
    {
        Array a;
        ofstream out("blabla.txt");
        out << a;
        // rest
    }
    

    dann sollte das doch auch gehen oder nich?



  • std:: bezeichnet lediglich den Namespace.
    Ob du jetzt std:: überall vorneran setzt oder einmal using namespace std; schreibst, dann ist das äquivalent. Jedoch Achtung! In einem Header könnte das ungewollte Folgen nach sich ziehen. Wenn es keinen guten Grund gibt, würde ich empfehlen überall den Namespace voreran zu setzen.



  • mir gings eigendlich um den stream

    also cout geht ja and en bildschirm aber ofstream an dateien

    das sollte dann auch klappen oder?



  • Das habe ich dir ja beantwortet, dass es keine Rolle spielt.. 🙄

    Um es klar zu sagen: "Ja, das geht auch so!". Aber warum hast du das nicht einfach ausprobiert?!



  • aber ist es nicht übersichtlicher und sinnvoller den nur in der klasse zu überladen 
    sprich so wie ichs eigendlich vorhatte?
    

    jain.
    Es ist schon besser, den Operator in der Klasse zu überladen, aber in diesem Fall nicht möglich, weil du nicht den Operator der Arrayklasse überladen müsstest sondern den der ostream Klasse.
    Wenn du den Operator in der Klasse überlädst kannst du auch nur einen Parameter angeben und das ist der zweite.

    Aaaber, es gibt noch eine Möglichkeit das in der Klasse zu schreiben, aber die solltest du eigentlich nicht nutzen, da es nicht zur Klasse gehört und die Kapselung bricht.
    Du kannst ein friend vor die Operatorüberladung setzen
    (also:
    [cpp} friend ostream& operator << (ostream& stream, Array const& obj)
    {
    obj.ausgeben(stream);
    return stream;
    }[/cpp])



  • So siehts aus schrieb:

    aber ist es nicht übersichtlicher und sinnvoller den nur in der klasse zu überladen 
    sprich so wie ichs eigendlich vorhatte?
    

    jain.
    Es ist schon besser, den Operator in der Klasse zu überladen, aber in diesem Fall nicht möglich, weil du nicht den Operator der Arrayklasse überladen müsstest sondern den der ostream Klasse.
    Wenn du den Operator in der Klasse überlädst kannst du auch nur einen Parameter angeben und das ist der zweite.

    Aaaber, es gibt noch eine Möglichkeit das in der Klasse zu schreiben, aber die solltest du eigentlich nicht nutzen, da es nicht zur Klasse gehört und die Kapselung bricht.
    Du kannst ein friend vor die Operatorüberladung setzen
    (also:
    [cpp} friend ostream& operator << (ostream& stream, Array const& obj)
    {
    obj.ausgeben(stream);
    return stream;
    }[/cpp])

    Dann gehört operator<< auch nicht zur Klasse, sondern hat lediglich zugrtiff auf deren private Elemente.
    Und Friend-Funktionen/Klasse weichen nicht zwangsläufig die Kapselung auf. Es gibt auch sinnvolle Anwendungen, wo, im Gegenteil, die Kapselung gestärkt wird.



  • Ist schon klar, ging ja nur darum, dass er gesagt hat, es sei übersichtlicher in der Klasse und nicht darum, das wirklich der Klasse zugehörig zu machen.



  • Hallo,
    Ich hab ein ganz ähnliches Problem.
    Habe eine KLasse FELD geschrieben (nur zum Üben von C++). Objekte dieser Klasse sind char - Arrays. Wenn ich jetzt neue Objekte erzeuge und diese mit Srtings initialisiere, dann klappt das auch. Nur die Ausgabe auf den Bildschirm klappt nicht, und ich weiß nicht warum. Hab die freie Ausgabefunktion als friend der Klasse deklariert und trotzdem kann die Funktion nicht auf die privaten Attribute der KLasse zugreifen!!???
    -------------------------------------------------------

    // Feld.h
    #include <iostream>
    using namespace std;
    
    class CFeld  
    {
    	friend ostream& operator<<(ostream&, const CFeld&);
    public:
    	CFeld(char*);
    	CFeld(const CFeld&);
    	CFeld();
    	virtual ~CFeld();
    
    private:
    	char* startptr;
    	int dim;
    };
    
    #endif
    -------------------------------------------------------
    
    Feld.cpp
    
    #include <iostream>
    using namespace std;
    #include "Feld.h"
    #include "string.h"
    
    //////////////////////////////////////////////////////////////////////
    // Konstruktion/Destruktion
    //////////////////////////////////////////////////////////////////////
    
    CFeld::CFeld()
    {
    	dim = 0;
    	startptr = NULL;
    }
    
    CFeld::~CFeld()
    {
    
    }
    
    CFeld::CFeld(const CFeld& feld)
    {
    	dim = feld.dim;						
    	startptr = new char[dim];
    	for (int i = 0; i <= dim; i++)
    		startptr[i] = feld.startptr[i];
    }
    
    CFeld::CFeld(char* string)
    {
    	for(int i = 0; string[i] != '\0'; i++);
    	dim = i;
    	startptr = new char[dim];
    	strcpy(startptr, string);
    }
    
    ostream& operator<<(ostream& os, const CFeld& feld)
    {
    	for(int i = 0; i < (feld.dim); i++)
    	{
    		os << feld.startptr[i];
    
    	}
    	return os;
    }
    ---------------------------------------------------------------
    
    main.cpp
    
    #include <iostream>
    using namespace std;
    
    #include "Feld.h"
    
    void main (void)
    {
    	CFeld s1 = "Guten";
    	CFeld s2 = "Morgen";
    
    	CFeld s3;
    
    	CFeld s4 = s1;
    	CFeld s5 = s2;
    
    	cout<<s1<<" "<<s2<<endl;
    
    }
    

    ---------------------------------------------------

    Kann mir da jemand helfen???

    Viele Grüße

    /edit pumuckl: cpp-Tags, demnächst bitte selbst machen!



  • Schau Dir nochmal genau an, was Du hier treibst:

    CFeld::CFeld(char* string)
    {
        for(int i = 0; string[i] != '\0'; i++);
        dim = i;
        startptr = new char[dim];
        strcpy(startptr, string);
    }
    


  • Tachyon schrieb:

    Also als Friend deklarieren und dann global überladen.

    warum als friend?



  • 😕 hab folgende Programme geschrieben

    #include <string> 
    
    class mann 
    { 
      public: 
        mann(std::string name) 
          : Name(name) 
        { 
        } 
    
        friend std::ostream &operator<<(std::ostream &ostr, mann &m); 
    
      private: 
        std::string Name; 
    }; 
    
    #include "mann.h" 
    #include <iostream> 
    
    std::ostream &operator<<(std::ostream &ostr, mann &m) 
    { 
      return ostr << m.Name; 
    } 
    
    #include "mann.h" 
    #include <iostream> 
    
    int main() 
    { 
      mann m("Meier"); 
      std::cout << m << std::endl; 
    }
    

    Das hab ich dann auch kompiliert und läuft. Aber folgendes Programm läuft nicht da bekomm ich fehlermeldungen:

    make
    g++ -g -c zeit.cc -o zeit.o
    In file included from zeit.cc:1:0:
    zeit.h:82:79: error: non-member function ‘std::ostream& std::operator<<(std::ostream&, const std::zeit&)’ cannot have cv-qualifier
    zeit.cc:203:71: error: non-member function ‘std::ostream& operator<<(std::ostream&, const std::zeit&)’ cannot have cv-qualifier
    make: *** [zeit.o] Fehler 1
    
    // Sicherstellen daß zeit.h nur einmal benutzt wird
    #ifndef ZEIT_H
    #define ZEIT_H
    
    #include <fstream>
    
    namespace std{
        class zeit
        {
        protected:
    	long int zeitpunkt;
    
        public:
    	// ctor
    	zeit();
    	// allg. ctor mit default-Werten 
    	zeit(int sommerzeit, int tag, int monat, int jahr, int stunde, int minuten);
    	// Copy ctor
    	zeit( const zeit& _zeitpunkt );
    	// dtor
    	virtual ~zeit() {};    // Ohne Funktionalität, für abgeleitete Klassen
    
    	// Funktion zum setzen der Messzeit mit Vorgabewerten
    	virtual bool setZeitpunkt(int sz = 0, int t = 1, int m = 0, int j = 0, int s = 0, int min = 0);
    	virtual bool setZeitpunkt(long int _z) {zeitpunkt = _z;};
    	// Zum setzen des Zeitpunkts auf Systemzeit des Rechners
    	virtual bool setHeute();
            // Funktion um den Tag zu ändern
    	virtual bool setTag(int _day);
            // Monatsänderung
    	virtual bool setMonat(int _month);
            // Jahresänderung
    	virtual bool setJahr(int _year);
            // Stundenänderung
    	virtual bool setStunde(int _hour);
            // Minutenänderung
    	virtual bool setMinute(int _minute);
    
    	// Gibt den Wert des Zeitpunkts zurück als zahl
    	virtual long int getZeitpunkt() const;
            // Gibt den Tag als Zahl zurück
    	virtual int getTag() const;
            // Gibt den Monat als Zahl zurück
    	virtual int getMonat() const;
            // Gibt das Jahr als Zahl zurück
    	virtual int getJahr() const;
            // Gibt die Stunde als Zahl zurück
    	virtual int getStunde() const;
            // Gibt die Minute als Zahl zurück
    	virtual int getMinute() const;
     	// Bildschirmausgabe der Zeit in Form: tt.mm.jjjj ss:mm
    	virtual std::ostream& ausgabe(std::ostream& stream) const;
    
    	// freund da ostream nicht direkt zugreifbar...
    	friend std::ostream& operator<<(std::ostream& output, const std::zeit& wann) const;
        };
    }
    //--------------------------------------------------------------------
    // friend operator zur ausgabe....
    //--------------------------------------------------------------------
    std::ostream& operator<<(std::ostream& output, const std::zeit& wann) const
    {
    	std::ostringstream ss;
    
    	ss << std::setw(2) << std::setfill('0') << wann.getTag();
    
    	return(output << ss);
    }
    

    kann mir jemand sagen was ich falsch mache? Bin schon über eine Woche am suchen und finde den Fehler nicht?

    /edit pumuckl: code-Tags bitte nochmal üben 😉



  • Die Fehlermeldungen sind doch relativ eindeutig:

    zeit.h:82:79: error: non-member function ‘std::ostream& std::operator<<(std::ostream&, const std::zeit&)’ cannot have cv-qualifier
    zeit.cc:203:71: error: non-member function ‘std::ostream& operator<<(std::ostream&, const std::zeit&)’ cannot have cv-qualifier

    Mit cv-qualifier ist das "const" in am Ende der Zeilen 55 und 61 deines Codes gemeint.
    Der operator<< ist keine Memberfunktion, sondern nur ein friend der Klasse, weswegen du ihn nicht als "const" deklarieren kannst.



  • danke sehr, aber jetzt bin ich nicht wirklich weiter, die referenz sollte doch eigentlich die operatorfunktion sein???

    [make
    g++ -g -c hauptfenster.cc -o hauptfenster.o
    g++ neulesen.o hauptfenster.o zeit.o zucker.o texfunctions.o -o programm
    hauptfenster.o: In function main': /home/karlscheidt/Dokumente/programmieren/programme\_ks/versuche/zucker20062011/hauptfenster.cc:15: undefined reference tostd::operator<<(std::basic_ostream<char, std::char_traits<char> >&, std::zeit const&)'
    collect2: ld returned 1 exit status
    make: *** [programm] Fehler 1
    ]



  • nimm erstmal deine zeit-Klasse aus dem namespace std - der ist reserviert, da darf nicht jeder dran.
    Danach schau mal in die FAQ, da gibts einen Eintrag zum Thema "undefined reference"



  • Vielen dank pumuckl,

    hab namespace std aus dem Programm genommen und jetzt funktionierts wenn ich auch noch nicht blicke warum, aber warscheinlich find ich diese Lösung bei Stroustrup...

    aber eine andere Frage, was meintest du mit sourcecode richtig einbinden? Da steh ich auf der Leitung?
    lg
    KS


Anmelden zum Antworten