Feststellen, welcher abgeleiteten Klasse ein Objekt angehört
-
Mein Programm schreibt muss in einer gewissen Reihenfolge Attribute eines Objektes per fstream und write() in eine Datei schreiben. Dieses Objekt kann einer beliebigen abgeleiteten Klasse einer gemeinsamen Basisklasse angehören. Bisher habe ich daher ganz einfach erst alle Attribute der Basisklasse und dann alle der abgeleiteten Klasse ausgegeben, indem ich eine virtuelle Methode nutzte, die für jede abgeleitete Klasse zuerst auf die entsprechende Methode der Basisklasse verweist. Aber in der Praxis geht das so nicht, weil das Format, das mein Programm schreiben soll, in manchen Fällen auch Attribute, die nur in der abgeleiteten Klasse vorkommen, zwischen denen der Basisklasse hat. Daher kann ich streng nach meiner bisherigen Technik nicht arbeiten.
Kurzfristig kam ich daher auf die Idee, einfach nur mit einer Methode in der Basisklasse zu arbeiten, die zur Laufzeit bestimmt, welcher abgeleiteten Klasse das Objekt angehört, und entsprechend handelt. Das würde zwar das Reihenfolgenproblem lösen, aber irgendwie grausam schlechter Stil sein, wenn man schon Klassen ableitet.
Also jetzt die Frage an die Community hier: Gibt es da eine Möglichkeit, irgendwie eine gegebene Reihenfolge einzuhalten und trotzdem nicht die gesamte Objektorientierung über den Haufen zu werfen.
(Ist natürlich eine relativ unkonkrete Frage, also reichen mir auch schon relativ unkonkrete Antworten
).
-
Ich weiß nicht ob ich dich richtig verstanden habe, aber ich glaube das was du suchst ist dynamic_cast.
-
vielleicht könntest du die Basisklassenversion des schreibens in der Datei in kleine Teile aufteilen, die immer nur stückchen schreiben und zwisdchen diese Stückchen kannst du dann die neuen Daten schreiben. Im extremfall wärs dann so, dass du für jedes Datum eine funktion hast, aber dann kannst du auch gleich die daten selber reinschreiben.
Die Basisklassenversion ruft dann die "Stückchenfunktionen" in der Reihenfolge auf, wies die basisklasse will, die abgeleiteten nehmen eine andere reihenfolge oder lassen auch funktionen aus usw.
-
Die beste Lösung wäre es natürlich, dein Ausgabeformat so umzuordnen, daß die Basisattribute am Stück ausgegeben werden können, dann ist der Ansatz über eine virtuelle Methode ideal.
Die zweitbeste Möglichkeit ist es, bei der virtuellen Methode zu bleiben und in der überschriebenen Version alle Attribute in beliebiger Reihenfolge auszugeben (sowohl die eigenen als auch die (protected) der Basisklasse).
Ein weiterer Ansatz liegt dazwischen und nennt sich "Template Methode" (nicht zu verwechseln mit C++ Templates:
void Basis::print(ostream& tgt) { tgt<<get_type()<<attrib1; print_block1(tgt); tgt<<attrib2; print_block2(tgt); ... }(die Methoden print_block1(ostream&) etc sind virtuell und können von abgeleiteten Klassen genutzt werden, um ihre jeweiligen Attribute auszugeben.
Wenn du unbedingt den Typ ermitteln willst, hast du noch dynamic_cast<> oder typeid() - aber das solltest du nur in äußersten Notfällen verwenden (normalerweise ist es besser, wenn dir egal sein kann, welche Klasse du da hast ;)).
Edit: Da habe wir den Beweis, es gibt doch noch schnellere User als mich

-
Klar, wenn ich das Format so umordnen könnte, wie ich es wollte, hätte ich das auch schon getan. (Ach, alles voller Konjunktive!)

Deine zweitbeste Möglichkeit ist relativ logisch und auch ich hatte sowas in der Art hier schon geplant zu nutzen, aber da stößt halt sauer auf, dass eine ziemliche Redundanz da ist, wenn man manche Sachen zwei oder mehrmals genau gleich schreibt.
Auch die Template-Variante ist sinnvoll, aber möglicherweise Overkill angesichts meiner Situation. Die ist nämlich, um konkreter zu werden, dass nur eine einzige Zeile in den Basisklassen-Block ergänzt werden müsste. Da bin ich schon sehr versucht, einfach nur ein if-Statement in der Basismethode zu schreiben, denn das scheint mir ein akzeptabler Kompromiss zu sein. Die Frage ist nur, ob ich der Basisklasse ein Flag-Attribut gebe, dass auf einen gewissen Wert gesetzt wird, wenn man eine bestimmte abgeleitete Klasse hat, oder ob ich das dann wiederum mit typeid zur Laufzeit bestimme. Beide Methoden sind nicht gerade pure Eleganz, aber sollten ihre Arbeit erledigen, wie erwartet.
Edit: Mir fällt gerade ein, dass obiges ja eher nicht geht, weil ich in der Methode der Basisklasse ja nicht auf ein Attribut der abgeleiteten Klasse zugreifen kann...
-
David Schneider schrieb:
Auch die Template-Variante ist sinnvoll, aber möglicherweise Overkill angesichts meiner Situation. Die ist nämlich, um konkreter zu werden, dass nur eine einzige Zeile in den Basisklassen-Block ergänzt werden müsste.
Wenn diese "einzige Zeile" immer an der selben Stelle hinkommen soll, passt der "Template Methode" Ansatz doch perfekt auf dein Problem:
class Basis { public: void print(ostream& out) { //viele Ausgaben print_sub(out); //weitere Ausgaben } protected: virtual void print_sub(ostream& out)=0;//hier geben die abgeleiteten Klassen ihre "einzige Zeile" aus };Da bin ich schon sehr versucht, einfach nur ein if-Statement in der Basismethode zu schreiben, denn das scheint mir ein akzeptabler Kompromiss zu sein. Die Frage ist nur, ob ich der Basisklasse ein Flag-Attribut gebe, dass auf einen gewissen Wert gesetzt wird, wenn man eine bestimmte abgeleitete Klasse hat, oder ob ich das dann wiederum mit typeid zur Laufzeit bestimme. Beide Methoden sind nicht gerade pure Eleganz, aber sollten ihre Arbeit erledigen, wie erwartet.
Ja, das hätte etwas, nur dürfte sich dieses "nur ein if-Statement" dann zu einer länglichen if-else-Kaskade ausweiten, in der du nacheinander alle möglichen Subtypen per dynamic_cast durchtestest
(und wenn du einen weiteren Sub-Typ ergänzt, mußt du die noch weiter in die Länge ziehen)
-
Stimmt. Na dann werde ich das mal so einbauen. Danke für die Hilfe.