Hallo, ich bin bei C++ absoluter Anfänger, also bitte nicht hauen für die dumme Frage... Zur Übung soll ich ein Programm "Autovermietung" programmieren. Es gibt eine Klasse "Kunde" und eine Klasse "Fahrzeug", jeweils als doppelt verkettete Liste. Die Objekte der Klasse "Kunde" enthalten Zeiger vom Typ "Fahrzeug", der auf das gemietete Fahrzeug zeigt, wenn der Kunde eines gemietet hat. Die Objekte der Klasse "Fahrzeug" enthalten Zeiger vom Typ "Kunde", der auf den Kunden zeigt, der das Fahrzeug gemietet hat. Ich habe die Klassendefinitionen und das Hauptprogramm in eine einzige Datei geschrieben. Der Compiler ist Dev C++ "Bloodshed", weil der Lehrstuhl den empfohlen hat. Beim Kompilieren kriege ich Fehlermeldungen: Wenn die Kunden-Klasse vor der Fahrzeug-Klasse in der Datei kommt, kann der Compiler nichts mit dem Zeiger auf das Fahrzeug-Objekt anfangen, wenn die Fahrzeug-Klasse vor der Kunden-Klasse kommt, kann der Compiler nichts mit dem Zeiger auf das Kunden-Objekt anfangen. Wenn ich erst Kunden-Klasse und dann Fahrzeug-Klasse definiere, und am Anfang der Datei, vor der Kunden-Klasse einfach deklariere: class Fahrzeug{}; dann kriege ich eine Fehlermeldung "redefinition of class Fahrzeug". Dürfen Klassen in C++ einfach nicht gegenseitig aufeinander zeigen? Oder gibt es einen Trick, wie man sowas kompilieren kann? Danke, Philipp
Du musst die geschweiften Klammern weglassen. class x; ist eine Deklaration class x{}; ist eine Definition
Markus_Bauer schrieb: > Ich habe die Klassendefinitionen und das Hauptprogramm in eine einzige > Datei geschrieben. Der Compiler ist Dev C++ "Bloodshed", weil der > Lehrstuhl den empfohlen hat. das ist eine IDE, der Compiler wird wahrscheinlich der GCC sein. > Dürfen Klassen in C++ einfach nicht gegenseitig aufeinander zeigen? Oder > gibt es einen Trick, wie man sowas kompilieren kann? dürfen sie. Genau, wie man bei Funktionen zwischen Deklaration und Definition unterscheidet, kann man das auch bei Klassen:
1 | class Fahrzeug(); |
ohne {} wäre eine Deklaration (auch manchmal "forward declaration" genannt). Die reicht, damit Du den Typen im Zusammenhang mit Zeigern und Referenzen verwenden kannst. mfg Torsten p.s.: Auch wenn ihr es in der Schule lernt: verkette Listen schreibt keiner von Hand.
Sorry, ich habe Unsinn geschrieben. Der Compiler meckert erst, wenn ich in der Kunden-Klasse eine public-Methode der Fahrzeugklasse aufrufen will. Z.B. wenn ich in einer Methode der Kunden-Klasse eine publi-Methode der Fahrzeugklasse aufrufen will. Konkret will ich Kundendaten ausgeben und dabei den Typ des gemieteten Fahrezeugs ausgeben. Ich habe also einen Zeiger auf das gemietete Fahrzeug und möchte dann eine public-Methode des Fahrzeugs aufrufen, z.B mit gemietet->getTyp() "gemietet" ist der Name des Zeigers, "getTyp" der Name der public-Methode des Fahrzeug-Objekts. Sie soll einen string zurückgeben. Ich kriege leider den Compiler-Fehler "getTyp has not been declared". Wie kann ich die Methode deklariere, ohne dass ich die "redefinition"-Fehlermeldung kriege? Danke
Teile den Code einfach richtig auf, Beispiel, ungetestet:
1 | // a.hpp
|
2 | class b; // b als klasse deklarieren |
3 | class a { // klasse a definieren |
4 | private:
|
5 | b* v; // member definieren |
6 | public:
|
7 | void setv(b*); // memberfunktion declarieren |
8 | }
|
9 | |
10 | // b.hpp
|
11 | class a; // b als klasse deklarieren |
12 | class b { // klasse a definieren |
13 | private:
|
14 | a* v; // member definieren |
15 | public:
|
16 | void setv(a*); // memberfunktion declarieren |
17 | }
|
18 | |
19 | // a.cpp
|
20 | #include<a.hpp> |
21 | #include<b.hpp> |
22 | void a::setv(b*x){v=x;} |
23 | |
24 | // b.cpp
|
25 | #include<b.hpp> |
26 | #include<a.hpp> |
27 | void b::setv(a*x){v=x;} |
Um einen Zeiger auf etwas zu deklarieren, muss der Compiler nur wissen, dass es etwas gibt (forward declaration): class Fahrzeug; So geht es nicht:
1 | class Fahrzeug{}; // hiermit deklariere ich die Klasse Fahrzeug, die nichts enthält. |
2 | |
3 | class Garage |
4 | {
|
5 | Fahrzeug* bla; |
6 | };
|
7 | |
8 | class Fahrzeug // Hiermit deklariere ich wieder die Klasse Fahrzeug, die |
9 | { // diesmal einen Garagen-Zeiger enthält. => Widerspruch. |
10 | Garage* g; |
11 | };
|
So geht es:
1 | class Baum; // Hallo Compiler, es gibt eine Klasse "Baum", Details folgen später |
2 | |
3 | class Apfel |
4 | {
|
5 | public:
|
6 | Apfel(Baum* b) : mein_baum(b) |
7 | {
|
8 | }
|
9 | |
10 | Baum* mein_baum; // Zeiger ist Zeiger, der Compiler muss dazu nicht wissen, |
11 | // wie Baum intern aufgebaut ist, nur, dass die Klasse existiert
|
12 | };
|
13 | |
14 | class Baum |
15 | {
|
16 | public:
|
17 | Baum() |
18 | {
|
19 | }
|
20 | |
21 | Apfel* meine_frucht; |
22 | |
23 | void wachse() |
24 | {
|
25 | meine_frucht = new Apfel(this); |
26 | }
|
27 | };
|
Torsten R. schrieb: > Auch wenn ihr es in der Schule lernt: verkette Listen schreibt > keiner von Hand. Das sollte man aber trotzdem können.
Ersetze "deklariere ich die Klasse" jeweils durch "definiere ich die Klasse".
Tom schrieb: > Um einen Zeiger auf etwas zu deklarieren, muss der Compiler nur wissen, > dass es etwas gibt (forward declaration): class Fahrzeug; Das funktioniert, danke. Sieht so aus: <c> class Fahrzeug; class Kunde { private: Fahrzeug* gemietet; .... public: void ausgabe() {cout << gemietet->getTyp();} //hier kommt der Compilerfehler ... }; class Fahrzeug { private: Kunde* vermietet; string typ; ... public: string getTyp() {return typ;} ....}; </c> Wahrscheinlich muss ich die Methode "getTyp" vor der Klasse "Kunde" irgendwie deklarieren, oder? Vielen Dank euch allen
Markus_Bauer schrieb: > Tom schrieb: >> Um einen Zeiger auf etwas zu deklarieren, muss der Compiler nur wissen, >> dass es etwas gibt (forward declaration): class Fahrzeug; > > Das funktioniert, danke. Sieht so aus: > > <c> > class Fahrzeug; > > class Kunde > { > private: > Fahrzeug* gemietet; > .... > public: > void ausgabe() > {cout << gemietet->getTyp();} //hier kommt der Compilerfehler > ... > }; > > class Fahrzeug > { > private: > Kunde* vermietet; > string typ; > ... > public: > string getTyp() > {return typ;} > ....}; > </c> > > Wahrscheinlich muss ich die Methode "getTyp" vor der Klasse "Kunde" > irgendwie deklarieren, oder? Ja, indem du die Klasse definierst, bevor du getTyp aufrufst. Wie schon gesagt wurde, wäre es sinnvoller, das sauber auf mehrere Dateien aufzutrennen und nicht alles in eine reinzuwurschteln.
1 | class Fahrzeug; |
2 | |
3 | class Kunde |
4 | {
|
5 | private:
|
6 | Fahrzeug* gemietet; |
7 | ....
|
8 | public:
|
9 | void ausgabe(); |
10 | ...
|
11 | };
|
12 | |
13 | class Fahrzeug |
14 | {
|
15 | private:
|
16 | Kunde* vermietet; |
17 | string typ; |
18 | ...
|
19 | public:
|
20 | string getTyp(); |
21 | {
|
22 | return typ; |
23 | }
|
24 | };
|
25 | |
26 | void Kunde::ausgabe() |
27 | {
|
28 | cout << gemietet->getTyp(); |
29 | }
|
Wie werden Objekte deiner Klassen erzeugt und wieder freigegeben? Wenn du so weit bist, dass das ganze compiliert, könnte das mit dem Freigeben zu einem Problem werden. Weil, wenn die gegenseitig aufeinander zeigen, und du gibst ein Objekt frei, dann hat das andere Zeiger, die ins Leere zeigen. Wenn du nicht aufpasst. Ist nicht schlimm, du darfst diese Zeiger dann aber nicht mehr dereferenzieren (das Objekt, auf das sie mal gezeigt haben, benutzen).
Sebastian schrieb: > Wie werden Objekte deiner Klassen erzeugt und wieder freigegeben? Würde mich nicht wundern, wenn selbst der Prof dabei Fehler macht ;-)
Torsten R. schrieb: > Würde mich nicht wundern, wenn selbst der Prof dabei Fehler macht ;-) Mich würde eher wundern, wenn er keine macht :)
guest schrieb: > Torsten R. schrieb: >> Würde mich nicht wundern, wenn selbst der Prof dabei Fehler macht ;-) > > Mich würde eher wundern, wenn er keine macht :) Und mich würde wundern wenn ein Prof auf die Idee käme das ein Kunde nicht nur ein Auto mieten kann :-))
Moin, Anstatt irgend welche circularen Abhängigkeiten zu erzeugen, solltest du lieber eine Verwaltungsklasse erstellen, welche Autos und Miete zusammen bringt. Dann braucht das Auto selber nicht zu wissen, an wenn es gerade vermietet ist und der Mieter muss es sich auch nicht merken ;) Bin ja positiv überrascht, das der dev-c++ mal wieder weiter entwickelt wird. Wobei 2016 ja offensichtlich nichts gemacht wurde.
Markus_Bauer schrieb: > Zur Übung soll ich ein Programm "Autovermietung" programmieren. Es gibt > eine Klasse "Kunde" und eine Klasse "Fahrzeug", jeweils als doppelt > verkettete Liste. Die Objekte der Klasse "Kunde" enthalten Zeiger vom > Typ "Fahrzeug", der auf das gemietete Fahrzeug zeigt, wenn der Kunde > eines gemietet hat. Die Objekte der Klasse "Fahrzeug" enthalten Zeiger > vom Typ "Kunde", der auf den Kunden zeigt, der das Fahrzeug gemietet > hat. Im realen Leben fehlt hier eine Klasse "Vertrag", die jeweils eine Referenz (oder meinetwegen einen Pointer) auf den Kunden und auf das FZ beinhaltet. Schließlich kann ein Firmenkunde gleichzeitig mehrere Fahrzeuge mieten, und irgendwo sollten wohl auch die Vertragsdetails (Mietbeginn und -ende, Preis, inkludierte Kilometer, ...) gespeichert werden. Letztlich können wir Dir bei Deinen Problemen sicher besser helfen, wenn Du uns Deinen Quellcode zeigst. ;-)
>mehrer Klassen, die gegenseitig aufeinander zeigen
Wirf an einer Schule eine Scheibe ein und brülle: "Wer war das?". Du
wirst sehen: mehrere Klassen, die gegenseitig aufeinander zeigen
:)
MfG Paul
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.