Abstrakte Klasse
-
Das mit dem Pure Destructor würde klappen vielen Dank

Zu dem Design: Da könntet Ihr recht haben. Denn meine nächste Frage wäre wie ich in der Methode die ein Fahrzeug bekommt herausbekommen würde was übergeben worden ist.
Methoden der Klasse Fahrzeug:
SetSpeed()
GetSpeed()
SetPrice()
GetPrice()
...Methoden der Klasse Fahrrad:
SetLenkradGepäckträger()
GetLenkradGepäckträger()Methoden der Klasse Auto:
SetAnhängerkupplung()
GetAnhängerkupplung()In den Methoden der Klasse Fahrzeug steckt eine Menge Code zur Überprüfung drin. Deshalb soll dieser nur einmal auftreten. In meiner Hauptapplikation muß aber ein komplettes Fahrzeug da sein. Fahrrad oder Auto. Wie würde ich nun herausbekommen was mir übergeben wurde?
-
Zur Not kann man auch den Konstruktor protected machen.
-
entschuldige, war eine Schludrigkeit meinerseits, um das Ganze kuerzer zu gestalten.
-
Also da ist dein Desing tatsächlich kaputt - entweder du schreibst dir Überladungen für alle Fahrzeug-Typen, die dann auf den jeweiligen Typ spezialisiert sind, oder du verwedest d*** (ich empfehle ersteres - oder eine Überarbeitung des Designs).
-
martin_salo schrieb:
In den Methoden der Klasse Fahrzeug steckt eine Menge Code zur Überprüfung drin. Deshalb soll dieser nur einmal auftreten. In meiner Hauptapplikation muß aber ein komplettes Fahrzeug da sein. Fahrrad oder Auto. Wie würde ich nun herausbekommen was mir übergeben wurde?
Ohne typecasts oder typeid (die meist unschoen sind) garnicht. Normalerweise solltest du auch nicht die Typinformation verlieren, wenn du wissen musst, womit du nun genau arbeitest. Lediglich Funktionen, denen egal ist, ob sie nun mit einem Fahrrad oder einem Auto arbeiten, koennen einfach ein Fahrzeug akzeptieren.
void RenoviereAnhaengerkupplung(Auto& a) { // Es waere sinnlos, das bei einem Fahrzeug zu machen, weil nur Autos sowas haben } void KLemmeAufGepaecktraeger(Fahrrad& f, Gepaeckstueck& g) { // geht bei Fahrzeugen allgemein nicht, nur bei Fahrraedern } void Verkaufe(Fahrzeug& f) { f.SetPrice(); //geht fuer alle fahrzeuge... }Nur wenn du beispielsweise einen Haufen fahrzeuge in einen Container geworfen hast und sie hinterher auseinanderosrtieren musst, ist es wichtig, den Typ wieder rauszufinden.
-
Kommando zurück. Ich habs:
Ich mache zwei Methoden in meinem Hauptobjekt:
Anstatt:
SetFortbewegungsmittel(Fahrzeug &Obj);
Mache ich:
SetFortbewegungsmittel(Auto &Obj);
SetFortbewegungsmittel(Fahrrad &Obj);Und Auto/Fahrrad leite ich wie bisher von Fahrzeug ab. In SetFortbewegungsmittel() kann ich dann kein Fahrzeug mehr übergeben...
-
Kannst du so oder so nicht, da Fahrzeug dank pure virtual Methoden eine abstrakte Klasse ist. Sprich: zur laufzeit deines Programms gibt es nur Autos, Fahrraeder, meinetwegen auch Trecker oder Zuege, aber keine reinen Fahrzeuge. Und falls du auch noch spaeter ein Motorrad zufuegen moechtest, muesstest du noch eine zusaetzliche Methode SetFortbewegungsmittel(Motorrad& m) definieren usw. Bis dahin hast du also mit der KLassenhierarchie garnichts gewonnen. Zeig doch mal, was du bisher hast, und erklaer uns in groben Zuegen, was du damit erreichen willst.
-
In Fahrzeug sind sehr viele Methoden mit Code. Es sind Getter und Setter mit Überprüfung der Daten. Der Dekonstruktor ist pure virtual.
Methoden der Klasse Fahrzeug:class Fahrzeug { SetSpeed() {// Mit Code} GetSpeed() {// Mit Code} SetPrice() {// Mit Code} GetPrice() {// Mit Code} ... virtual ~Fahrzeug()=0; // Damit Fahrzeug nicht instanziiert werden kann. } // Rumpf zum Dekonstruktor: Fahrzeug:~Fahrzeug() { // Dieser Dekonstruktor wird aufgerufen bei der Zerstörung eines Autos/Fahrrads. delete obj1; delete obj2; ... }Die Klassen Fahrrad und Auto haben alle Getter und Setter von Fahrzeug und zusätzlich ein paar Extra Methoden:
Beispielsweise Methoden der Klasse Fahrrad:
class Fahrrad : public Fahrzeug { SetLenkradGepäckträger() {// Mit Code} GetLenkradGepäckträger() {// Mit Code} ~Fahrzeug() { :~Fahrzeug(); // Objekte der Basisklasse zerstören. delete abc; } }In meiner Hauptklasse habe ich dann zwei Methoden:
SetFortbewegungsmittel(Fahrrad &F) { } SetFortbewegungsmittel(Auto &A) { }Ich muß eh beide Objekte unterschiedlich behandeln. Wenn jetzt noch ein Motorrad hinzukommt hat es auch extra Daten Getter/Setter, so dass ich in meiner Hauptklasse sowieso eine neue Methode machen muß.
-
martin_salo schrieb:
~Fahrzeug() { //sollte wohl Fahhrad heissen :~Fahrzeug(); // Objekte der Basisklasse zerstören. delete abc; }Den Basisklassen Destruktor brauchst du meines Wissens nicht aufzurufen, da die Basisklassen bestandteile immer zerstoert werden, und zwar nach Ausfuehrung des abgeleiteten Destruktors. damit wird auch sichergestellt, dass etwaige abhaengige Aktionen nicht auf ein schon zerstoertes Objekt zugreifen.
Bisher erkenne ich allerdings nicht, wie du in deiner Hauptklasse mit den Fahrzeugen umgehen willst. Wenn du schon bei SetFortbewegungsmittel zwischen den verschiedenen Typen unterscheidest, musst du das vermutlich auch bei der Verwendung in der Hauptklasse, und das widerum klingt nach unmengen von if-else kaskaden bzw. switch-cases
-
~Fahrzeug() { :~Fahrzeug(); // Objekte der Basisklasse zerstören. delete abc; }funzt das übehaupt? ist das std-konform? kommt es da zur laufzeit nicht zu einem bösen absturz??
und überhaupt was soll das bringen???allg.:
class Base{ public: Base() {std::cout<<"Base"<<std::endl; } virtual ~Base(){ std::cout<<"~Base"<<std::endl;} }; class D1 : public Base { D1 () {std::cout<<"D1 "<<std::endl; } ~D1(){ std::cout<<"~D1 "<<std::endl;} }; class D2 : public D1 { D2 () {std::cout<<"D2 "<<std::endl; } ~D2(){ std::cout<<"~D2 "<<std::endl;} }; int main() { D2 d1; std::cout<<std::endl; }--> output
Base
D1
D2~D2
~D1
~Base
-
Zuerst war nur Auto da. Mein Aufgabe war das Programm auf Fahrrad zu erweitern. Das ist mir jetzt gelungen, ohne das ich den Code duplizieren musste (doppelter code in Fahrzeug ausgelagert). Mit den if Statements hast Du recht. Ich glaube aber nicht das ich da herum komme. Das Programm muß sich bei einem Fahrrad etwas anders verhalten.
Danke für den Tip mit dem Dekonstruktor.
-
Da solltest du versuchen, dieses unterschiedliche Verhalten IN den Klassen zu verpacken - in Form von virtuellen Methoden (siehe mein Beispiel oben - sowohl auto als auch fahrrad haben eine Methode fahre(), aber jede Klasse hat eine andere Art, wie sie fahren will).
-
@muffmolch:
Ich wollte sicherstellen das der Dekonstruktor aufgerufen wird. Wenn er zweimal aufgerufen wird wird ein Objekt zweimal deleted. Ich habe den Aufruf aber mitlerweile entfernt.
-
Sei nicht schuechtern, zeig doch einfach dein Programm und was es macht (evtl gekuerzt aufs wesentliche)
martin_salo schrieb:
@muffmolch:
Ich wollte sicherstellen das der Dekonstruktor aufgerufen wird. Wenn er zweimal aufgerufen wird wird ein Objekt zweimal deleted.Wenn du Glueck hast passiert nicht viel, aber wenn du im geerbten Destructor z.B. deletes stehen hast, wird beim zweiten mal delete aufgerufen mit einem Argument, das irgendwo aus dem bereits "zerstoerten" gelesen wird.
And we enter the dark shady realms of undefined behavior.
-
@CStoll: Meine Klassen stellen nur Datenobjekte dar die gefüllt werden. Sie haben nur ein Methode IsValid() die sagt ob das Klassenobjekt mit einem konsitentem Datensatz gefüllt wurde. Alle Datenklasse werden dann einer Klasse zur Verarbeitung gegeben. Würde ich alle Datenklassen mit der Verarbeitungsklasse zusammenlegen hätte ich eine Menge (für mich zu viele) Methoden.
Es widerspricht vielleicht etwas dem OO Ansatz Daten und Funktionen zusammenzufügen, für mich ist es aber schön übersichtlich.
class Fortbewegung { SetFahrzeug(Auto A); SetFahrzeug(Fahrrad F); AddInsasse(Person P); DoFortbewegung() throw (UngueltigeAngaben); IsValid() throw (UngueltigeAngaben); }Den Code kann ich nicht zeigen. Nur soviel es geht um ein Dateiformat in XML wo unterschiedliche Objekte abgespeichert werden. class Fortbewegung ist in Wirklichkeit class DateiformatXYZ.
-
martin_salo schrieb:
Es widerspricht vielleicht etwas dem OO Ansatz Daten und Funktionen zusammenzufügen, für mich ist es aber schön übersichtlich.
Nein, es widerspricht dem OOP-Ansatz, Daten und Methoden zu trennen. Da kannst du gleich auf Objektorientierung verzichten. Und glaub mir, spätestens wenn du weitere Fahrzeugtypen dazubekommst, bleibt von der Übersichtlichkeit nichts mehr übrig.
-
@CStoll: Hatte mich da verschrieben. Bei OO werden natürlich Daten und Funktionen zusammengelegt.
Was ich ändern könnte wäre bei Fahrzeug ein Unterobjekt mit Namen Spezialisierung zu setzen. Spezialisierung wäre dann ein Objekt vom Typ Auto oder Fahrrad. Da müsste ich den Anwendern meines Dateiformates aber wieder eine Menge beibringen. Sie müssten Objekte hierarchisch zusammenbauen. Auto in Fahrzeug packen und Fahrzeug dann in Dateiformat.
Alles hat seine Vor- und Nachteile.
-
Und geholfen hast du mit dem Design niemandem - du hast nur deine Fallunterscheidungen von der Klasse Dateiformat in die Klass Fahrzeug verlagert.
Nochmal: Wenn du objektorientiert arbeiten willst, dann bitte richtig - die Klasse Fahrzeug definiert eine feste Schnittstelle von Operationen (für dich von mir aus 'lies_ein()' und 'gib_aus()' als abstrakte Methoden) und die abgeleiteten Klassen überschreiben diese Methoden und bauen dort ihre eigene Art ein, sich einzulesen bzw. auszugeben.
-
@CStoll: Hm. Da Auto und Fahrrad in Wirklichkeit XML Objekte sind müsste ich jedem Objekt die Methoden lies_ein/WriteToXML und gib_aus/ReadFromXml geben. Und die XmlFile Klasse würde dann jedes der Objekte über die Methoden in das File schreiben oder davon lesen. Ok

-
Eine kleine Nachfrage: Was macht das public?
class XMLFormat : public BaseFormat {...}Es funktioniert auch wenn ich es weglasse...