Problem mit gegenseitiger abhängigkeit in Header-Files
-
Hallo Leute,
ich stehe gerade vor einem kleinen Problem und weiß nicht so ganz wie man sowas in C++ löst... Oder ob das überhaupt möglich ist...
Ich habe zwei Klassen, eine Klasse Auto und eine Service...
Die Klasse Auto muss die Klasse Service kennen und auch umgekehrt,
also Service muss Auto kennen...So sehen meine Header-Files aus:
#ifndef Uebungsblock_3_Aufgabe_1_Auto_h #define Uebungsblock_3_Aufgabe_1_Auto_h #include "Service.h" class Auto { friend class Service; public: Auto(); Auto(const std::string& kunde, double newVerbrauch, double newTankFuellung, int newKmStand = 0); double getVerbrauch() const; double getFuellung() const; int getKmStand() const; bool tanke(double liter); bool fahre(int km); private: double verbrauch; double maxTankFuellung; double tankFuellung; int kmStand; Service aService; }; #endif#ifndef Uebungsblock_3_Aufgabe_1_Service_h #define Uebungsblock_3_Aufgabe_1_Service_h #include "Auto.h" class Service { public: Service(); int getKmStandAuto(Auto& a); }; #endifNaja das Problem ist der Compiler weiß ja nicht wo er anfangen soll bzw. kann ja schlecht erst das Auto compalieren weil er Service nicht kennt und kann auch nicht Service compalieren weil er Auto nicht kennt...
Also bin ich in einem "Dead-Lock"...Wie löst man so ein Problem?
-
Sowas nennt man nicht Deadlock, sondern zirkuläre Includes. Service muss Auto nicht kennen. Eine Deklaration reicht bereits aus.
-
Vielen Dank für den Tipp, ich habe es einfach Dead-Lock genannt weil ich die richtige Bezeichnung dafür nicht kenne bzw kannte (:
Aber jetzt stehe ich vor einer weiteren Frage...
Also ich habe meine Header-Files wie folgt verändert:#ifndef Uebungsblock_3_Aufgabe_1_Auto_h #define Uebungsblock_3_Aufgabe_1_Auto_h #include "Service.h" class Auto { friend class Service; public: Auto(); Auto(const std::string& kunde, double newVerbrauch, double newTankFuellung, int newKmStand = 0); double getVerbrauch() const; double getFuellung() const; int getKmStand() const; bool tanke(double liter); bool fahre(int km); private: double verbrauch; double maxTankFuellung; double tankFuellung; int kmStand; Service aService; }; #endif#ifndef Uebungsblock_3_Aufgabe_1_Service_h #define Uebungsblock_3_Aufgabe_1_Service_h class Auto; class Service { std::string kunde; public: Service(const std::string& kunde); int getKmStandAuto(Auto& a); }; #endifIch hoffe das ist genau das was du gemeint hast...
Doch wenn ich dann mein Programm laufen lasse dann meckert er in der Implementierung von Service:#include <iostream> #include "Service.h" Service::Service(const std::string& kunde) :kunde(kunde) { } int Service::getKmStandAuto(Auto& a) { return a.kmStand; }Um genau zu sein in Zeile 11, dort sagt er mir "Member access into incomplete type "Auto"" ist ja auch klar, Auto ist ja nicht wirklich implementiert...
Wenn ich aber in dieser Filme noch ein #include "Auto.h" mache dann funktioniert es ohne Probleme...
Also dann sieht das ganze so aus:
#include <iostream> #include "Service.h" #include "Auto.h" Service::Service(const std::string& kunde) :kunde(kunde) { } int Service::getKmStandAuto(Auto& a) { return a.kmStand; }Meine Frage ist jetzt nur noch, macht man das wirklich genau so?
Oder gibts da einen etwas "besseren" bzw. "eleganteren" weg?
-
In der Implementierung muss Auto natürlich vollständig bekannt sein, daher wirst du um den Include nicht herumkommen.
-
Vielen Dank!
Aber noch eine kleine Frage,
hätte ich das auch umgekehrt machen können?
Also quasi bei Auto nur eine Deklaration und bei Service dann der include?
Bin leider nicht mehr am Computer sonst würde ich es einfach testen...
Eigentlich müsste es ja gehen, ich erkenne jetzt gerade nicht warum es nicht gehen sollte...
-
Nein, das geht nicht, weil Auto einen Member vom Typ Service hat. Aus diesem Grund muss die Größe eines Service-Objekts bekannt sein, wofür eine Deklaration nicht ausreicht.
-
Stimmt, hätte ich mir ja denken können...
Aber das bringt mich jetzt auf eine neue Frage...
Das wird dann wohl auch die letzt sein (:Was macht man wenn jeweils jede Klasse einen Member vom anderen hat?
Mir fällt jetzt kein Beispiel ein aber sagen wir jetzt einfach mal, dass Service auch einen Member von Auto bekommen soll, dann reicht ja die Deklaration auch nicht mehr...Was macht man dann?
-
Das ist einfach nicht möglich.
-
vandread schrieb:
Was macht man dann?
Ganz viel RAM kaufen.
-
vandread schrieb:
Was macht man wenn jeweils jede Klasse einen Member vom anderen hat?
Mir fällt jetzt kein Beispiel ein aber sagen wir jetzt einfach mal, dass Service auch einen Member von Auto bekommen soll, dann reicht ja die Deklaration auch nicht mehr...Es wird dir schwer fallen, ein solches Beispiel sinnvoll zu konstruieren.
Hier ist ein einfaches Argument:
Wenn eine Klasse T ein nichtstatisches Member des Typs U hat, gilt immer: sizeof(T)>=sizeof(U)In deinem Fall müsste das auch umgekehrt gelten: sizeof(U)>=sizeof(T)
Das funktioniert also nur, falls sizeof(T)==sizeof(U). Irgendwelche Informationen kann man in solchen Objekten offenbar nicht speichern, sofern sizeof(T)<∞, und für sizeof(T)==∞ bräuchtest du eine Menge Speicher...