[solved] Multiple Operator Overloading
-
hi
ich muss ein kleines programm schreiben das aus txt dateien gebiete und dazugehörige städte einliest, diese bearbeitet und formatiert wieder ausgiebt; aber ich habe ein problem bei der ausgabe für die ich den << operator überladen möchte;
für folgende klassen möchte ich diesen operator verwenden;
class Gebiet { public: ... friend ostream &operator<< ( ostream &s, const Gebiet &g ); private: ... string Name; }; ostream &operator<< ( ostream &s, const Gebiet &g ) { s << g.Name; return s;}
class Stadt { public: ... friend ostream &operator<< ( ostream &s, StadtListe &sl ); private: ... string Name; };
class StadtListe { public: ... friend ostream &operator<< ( ostream &s, StadtListe &sl ); private: vector<Stadt> Staedte; ... }; ostream &operator<< ( ostream &s, StadtListe &sl ) { for( unsigned i=0; i<sl.Staedte.size(); i++ ) { s << sl.Staedte[i].Name; } return s; }
versuche ich mit g++ zu kompilieren erhalte ich diesen fehler;
gebiet.o: In function `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Gebiet const&)': gebiet.cpp:(.text+0x0): multiple definition of `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Gebiet const&)' programm.o:programm.cpp:(.text+0x0): first defined here stadt.o: In function `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Gebiet const&)': stadt.cpp:(.text+0x0): multiple definition of `operator<<(std::basic_ostream<char, std::char_traits<char> >&, Gebiet const&)' programm.o:programm.cpp:(.text+0x0): first defined here stadt.o: In function `operator<<(std::basic_ostream<char, std::char_traits<char> >&, StadtListe&)': stadt.cpp:(.text+0x20): multiple definition of `operator<<(std::basic_ostream<char, std::char_traits<char> >&, StadtListe&)' programm.o:programm.cpp:(.text+0x20): first defined here collect2: ld returned 1 exit status
in programm.cpp werden lediglich listen für gebiete und städte angelegt und letztere soll dann mit dem überladenem << operator über cout ausgegeben werden;
#include "gebiet.h" #include "stadt.h" int main( int argc, char *argv[] ) { GebietListe GL( argv[1] ); StadtListe SL( argv[2], GL ); cout << SL; return 0; }
so wie ich die compiler fehler verstehe hakts daran dass ich << 2mal überlade was doch aufgrund der unterschiedlichen parameterliste kein problem sein sollte, oder ?
und eine zweite frage: muss man friend funktionen public deklarieren oder ist das egal ?
-
Das ist kein Compiler- sondern ein Linker-Error. Vermutlich hast du im Header wo der op<< für Gebiet definiert wurde die Includeguards vergessen. Siehe auch hier:
Ähnliche Diskussion
-
falls mit include guards
#ifndef GEBIET_HEADER #define GEBIET_HEADER ... #endif
gemeint ist, die hab ich bei beiden headern; ich hab sie nur nicht geschrieben damit der text net zu lang wird;
-
Schreib bitte nochmal genau in welchen Dateien die Deklarationen und Definitionen sind, wo du die Includeguards hast und was du wo einbindest.
Der Linker beschwert sich zumindest, dass du in stadt.cpp und gebiet.cpp in Zeile 1 (vermutlich über ein #include) die Definition von op<< für gebiet hast, obwohl der schon in programm.cpp, Zeile 1 definiert wurde (wahrscheinlich auch dort mit #include reingeholt)
Dann die selbe Beschwerde nochmal für den Stadtliste-operator, der in stadt.cpp definiert wird, obwohl er schon in programm.cpp definiert wurde.
-
nachdem was du vorhin geschrieben hast denk ich dass das problem ist dass ich in stadt.h gebiet.h inkludiere; aber wie liesse sich das vermeiden ? funktionieren forward deklarationen da überhaupt ?
programm.cpp
#include "gebiet.h" #include "stadt.h" int main( int argc, char *argv[] ) { GebietListe GL( argv[1] ); StadtListe SL( argv[2], GL ); cout << SL; return 0; }
gebiet.h
#ifndef GEBIET_HEADER #define GEBIET_HEADER #include <iostream> #include <set> #include <algorithm> using namespace std; class EOFException {}; class Gebiet { public: Gebiet( istream &s ) { s >> ID >> Name >> Obergebiet >> Typ; if( !s ) throw EOFException(); } Gebiet( unsigned pID ) { ID = pID; } bool operator< ( const Gebiet &G ) const { return ID < G.ID; } bool PrintOrder( const Gebiet *g ) const { if( Name < g->Name ) return true; else if( Name > g->Name ) return false; return false; } friend ostream &operator<< ( ostream &s, const Gebiet &g ); private: unsigned ID, Obergebiet; string Name; char Typ; }; class GebietListe { public: GebietListe( char * FileName ); Gebiet const *FindGebiet( unsigned ID ) const { Gebiet G( ID ); return &*Gebiete.find( G ); } private: set<Gebiet> Gebiete; }; ostream &operator<< ( ostream &s, const Gebiet &g ) { s << g.Name; return s; } #endif
gebiet.cpp
#include "gebiet.h" #include <fstream> GebietListe::GebietListe( char *FileName ) { ifstream g( FileName ); try{ for(;;) Gebiete.insert( g ); } catch( EOFException ) {} } /
stadt.h
#ifndef STADT_HEADER #define STADT_HEADER #include "gebiet.h" #include <vector> class StadtListe; class Stadt { public: Stadt( istream &s ) { s >> ID >> Name >> Einwohner >> GebietID >> Meereshoehe; if( !s ) throw EOFException(); } bool operator< ( const Stadt &s ) const { if( InGebiet->PrintOrder( s.InGebiet ) ) return true; if( s.InGebiet->PrintOrder( InGebiet ) ) return false; return Einwohner < s.Einwohner; } void LookupGebiet( GebietListe &gl ) { InGebiet = gl.FindGebiet( GebietID ); } Gebiet const *GetGebiet() const { return InGebiet; } friend ostream &operator<< ( ostream &s, StadtListe &sl ); private: unsigned ID, Einwohner, GebietID, Meereshoehe; string Name; Gebiet const *InGebiet; }; class StadtListe { public: StadtListe( char *FileName, GebietListe &gl ); void Print( ostream &o = cout ) const; friend ostream &operator<< ( ostream &s, StadtListe &sl ); private: vector<Stadt> Staedte; GebietListe &Gebiete; }; ostream &operator<< ( ostream &s, StadtListe &sl ) { for( unsigned i=0; i<sl.Staedte.size(); i++ ) { s << sl.Staedte[i].Name; } return s; } #endif
stadt.cpp
#include "stadt.h" #include <fstream> struct StadtOrder { bool operator() ( const Stadt *a, const Stadt *b ) const { return *a < *b; } }; StadtListe::StadtListe( char *FileName, GebietListe &gl ) : Gebiete( gl ) { ifstream s( FileName ); try { for( ;; ) Staedte.push_back( s ); } catch( EOFException ) {} for( unsigned i=0; i<Staedte.size(); i++ ) Staedte[i].LookupGebiet( gl ); } void StadtListe::Print( ostream &o ) const { set<const Stadt*, StadtOrder> SS; for( unsigned i=0; i<Staedte.size(); i++ ) SS.insert( &Staedte[i] ); const Gebiet *g = 0; for( set<const Stadt*, StadtOrder>::iterator i = SS.begin(); i != SS.end(); i++ ) { if( (*i)->GetGebiet() != g ) { g = (*i)->GetGebiet(); o << g; } o << *i; } }
-
Eine Forwarddeklaration von Gebiet in Stadt.h würde funktionieren, wenn du alle Funktionsdefinitionen welche Gebiet kennen müssen in die cpp verlagerst.
-
hm ich hab das jetzt versucht und das #include "gebiet.h" aus dem stadt header entfernt und stattdessen
class Gebiet; class GebietListe;
eingefügt; danach hab ich die entsprechenden funktionen aus stadt.h in stadt.cpp verlagert; dann bekomm ich folgende fehler;
stadt.cpp: In member function ‘bool Stadt::operator<(const Stadt&) const’:
stadt.cpp:13: error: invalid use of incomplete type ‘const struct Gebiet’
stadt.h:12: error: forward declaration of ‘const struct Gebiet’
stadt.cpp:14: error: invalid use of incomplete type ‘const struct Gebiet’
stadt.h:12: error: forward declaration of ‘const struct Gebiet’
stadt.cpp: In member function ‘void Stadt::LookupGebiet(GebietListe&)’:
stadt.cpp:19: error: invalid use of incomplete type ‘struct GebietListe’
stadt.h:13: error: forward declaration of ‘struct GebietListe’
make: *** [stadt.o] Error 1das "invalid use of incomplete type" kommt wohl daher dass gebiet.h nun fehlt; inkludiere ich es in stadt.cpp kommt wieder der fehler vom anfang; irgendwo muss ich diesen header also ohnehin in stadt.h oder stadt.cpp inkludieren;
-
Es bringt auch meistens nicht viel wenn man statt einem Fehler auf den Grund zu gehen versucht ihn zu umgehen und loszuwerden indem man "irgendwas" anders macht.
Was mir noch aufgefallen ist:
1)Du inkludierst in dem einen header <iostream>, im anderen nicht. Du solltest die Header überall dort einbinden, wo du sie brauchst, und zwar direkt, nicht nach dem Motto "ach, der ist schon über drei Ecken eingebunden, hier brauch ich den nichtmehr". In dem Fall reicht vermutlich <iosfwd> für beide.
2)Dann hast du nur "ostream" statt std::ostream in den headern stehen. Ich hoffe du hast dran gedacht, keine using-Direktiven in Headern zu benutzen.Wenn du das behoben hast, verschiebe mal die Definitionen der op<< in die entsprechende .cpp-Datei. Die friend-Deklaration in den Headern reicht schon aus, damit andere Übersetzungseinheiten sie dann auch benutzen können.
-
juhu das wars;
hab einfach alles so gemacht wie du geschrieben hast; danke für die hilfe;
eine letzte frage noch: warum ist es schlecht using in headern zu verwenden ?
-
Zenon schrieb:
eine letzte frage noch: warum ist es schlecht using in headern zu verwenden ?
Stell dir mal vor, dass jemand deinen Header inkludiert und du da
using namespace
für irgendeinen namespace machst. Der Benutzer weiss das nicht und definiert seine eigene Klasse, die zufälligerweise genau gleich heisst, wie eine aus dem namespace. Und dann hat er das Problem.