mikrocontroller.net

Forum: PC-Programmierung C++ mehrer Klassen, die gegenseitig aufeinander zeigen


Autor: Markus_Bauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jemand (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Du musst die geschweiften Klammern weglassen.
class x; ist eine Deklaration
class x{}; ist eine Definition

Autor: Torsten Robitzki (Firma: robitzki.de) (torstenrobitzki)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
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:
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.

Autor: Markus_Bauer (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
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

Autor: Daniel Abrecht (daniel-a)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Teile den Code einfach richtig auf, Beispiel, ungetestet:
// a.hpp
class b; // b als klasse deklarieren
class a { // klasse a definieren
  private:
    b* v; // member definieren
  public:
    void setv(b*); // memberfunktion declarieren
}

// b.hpp
class a; // b als klasse deklarieren
class b { // klasse a definieren
  private:
    a* v; // member definieren
  public:
    void setv(a*); // memberfunktion declarieren
}

// a.cpp
#include<a.hpp>
#include<b.hpp>
void a::setv(b*x){v=x;}

// b.cpp
#include<b.hpp>
#include<a.hpp>
void b::setv(a*x){v=x;}

Autor: Tom (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Um einen Zeiger auf etwas zu deklarieren, muss der Compiler nur wissen, 
dass es etwas gibt (forward declaration): class Fahrzeug;

So geht es nicht:
class Fahrzeug{}; // hiermit deklariere ich die Klasse Fahrzeug, die nichts enthält.

class  Garage
{
    Fahrzeug* bla;
};

class Fahrzeug  // Hiermit deklariere ich wieder die Klasse Fahrzeug, die 
{               // diesmal einen Garagen-Zeiger enthält. => Widerspruch.
    Garage* g;
};



So geht es:
class Baum; // Hallo Compiler, es gibt eine Klasse "Baum", Details folgen später

class Apfel
{
public:
    Apfel(Baum* b) : mein_baum(b)
    {
    }

    Baum* mein_baum; // Zeiger ist Zeiger, der Compiler muss dazu nicht wissen, 
                     // wie Baum intern aufgebaut ist, nur, dass die Klasse existiert
};

class Baum
{
public:
    Baum()
    {
    }

    Apfel* meine_frucht;

    void wachse()
    {
        meine_frucht = new Apfel(this);
    }
};

Torsten R. schrieb:
> Auch wenn ihr es in der Schule lernt: verkette Listen schreibt
> keiner von Hand.
Das sollte man aber trotzdem können.

Autor: Tom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ersetze "deklariere ich die Klasse" jeweils durch "definiere ich die 
Klasse".

Autor: Markus_Bauer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
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.
class Fahrzeug;

class Kunde
{
private:
  Fahrzeug* gemietet;
  ....
public:
  void ausgabe();
  ...
};
 
class Fahrzeug
{
private:
    Kunde* vermietet;
    string typ;
    ...
public:
    string getTyp();
    {
        return typ;
    }
};

void Kunde::ausgabe()
{
    cout << gemietet->getTyp();
}

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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).

Autor: Torsten Robitzki (Firma: robitzki.de) (torstenrobitzki)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian schrieb:
> Wie werden Objekte deiner Klassen erzeugt und wieder freigegeben?

Würde mich nicht wundern, wenn selbst der Prof dabei Fehler macht ;-)

Autor: guest (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Torsten R. schrieb:
> Würde mich nicht wundern, wenn selbst der Prof dabei Fehler macht ;-)

Mich würde eher wundern, wenn er keine macht :)

Autor: Hans-Georg Lehnard (h-g-l)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
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 :-))

Autor: nicht“Gast„ (Gast)
Datum:

Bewertung
4 lesenswert
nicht lesenswert
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.

Autor: Sheeva Plug (sheevaplug)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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. ;-)

Autor: Paul Baumann (paul_baumann)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
>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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.