'<<' 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-qualifierMit 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 functionmain': /home/karlscheidt/Dokumente/programmieren/programme\_ks/versuche/zucker20062011/hauptfenster.cc:15: undefined reference to
std::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