'<<' operator überladen



  • 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



  • thepower schrieb:

    hab namespace std aus dem Programm genommen und jetzt funktionierts wenn ich auch noch nicht blicke warum,

    Der namespace std ist reserviert, d.h du darfst nichts neues dort einführen. Punkt. Einzige Ausnahme sind Spezialisierungen für Templates aus namespace std, z.B. std::swap.

    Der Linkerfehler kam aber vermutlich eher daher, dass du operator<< zwar innerhalb der Klasse zeit im namensraum std als friend deklariert hast, aber ihn nicht im namensraum std definiert hast (sondern im globalen namensraum). ggf. wäre da die freind-deklaration so anzupassen gewesen, dass du den voll qualifizierten Namen (also ::operator<<) angeben müsstest.

    Aber wie gesagt, Finger weg von namespace std.



  • pumuckl schrieb:

    Einzige Ausnahme sind Spezialisierungen für Templates aus namespace std

    Ist das so? Ich dachte bisher, man darf nicht mal das.



  • 314159265358979 schrieb:

    pumuckl schrieb:

    Einzige Ausnahme sind Spezialisierungen für Templates aus namespace std

    Ist das so? Ich dachte bisher, man darf nicht mal das.

    Ja. Siehe dazu N3242 -> 17.6.4.2


  • Mod

    314159265358979 schrieb:

    pumuckl schrieb:

    Einzige Ausnahme sind Spezialisierungen für Templates aus namespace std

    Ist das so? Ich dachte bisher, man darf nicht mal das.

    Das war schon immer so, sofern selbstdefinierte oder von diesen abgeleitete Typen im Spiel sind.


Anmelden zum Antworten