Objecttyp ermitteln
-
Hallo zusammen,
ich würde gerne herausbekommen ob ein Objekt zu einem bestimmten Typ gehört.
Weiß aber leider nicht wie.
Beispiel:
Ich habe eine Elternklasse "Lebewesen" darunter gibt es ein Kind "Tier", darunter gibt es das Kind "Vierbeiner", darunter "Kuh".
Wenn ich jetzt eine Instanz der Klasse "Kuh" habe, möchte eine Methode einer anderen Klasse wissen, ob die Kuh
zB ein "Vierbeiner ist. Oder eine andere Frage wäre ist das Kuhobjekt ein "Tier" ist.
Wie kann ich das in C++ herausbekommen ? Ich bräuchte so etwas wie
a_Kuh->IsTypeOf( Tier ) ??Vielen Dank
Stephan
-
RTTI zur laufzeit
http://www.cpp-tutor.de/cpp/le16/le16_03.htm
-
Hallo,
erst einmal vielen dank für den Link.
Ich hab es jetzt mit typeid rumgespielt, da bekomme
ich den Typ der Klasse zurück. Im theoretischen Beispiel wäre das die "Kuh"
Aber woran erkenne ich ob die Kuh vom Typ "Tier" ist ?Grüße
Stephan
-
dynamic_cast
-
Hallo,
äh, euch ist aber schon klar, dass C++ eine statisch typ-geprüfte Sprache ist, oder?Konkret: Erstmal funktionieren upcasts völlig automatisch. Und aus der statischen Typisierung folgt, dass jede Methode die eine Kuh erhält per Definition weiß, dass selbige ein Tier ist. Kein Grund RTTI zu bemühen.
Andersrum (vom Tier zur Kuh) wäre das technisch nötig. In diesem Fall wäre aber das Design fragwürdig.
-
Hier möchte ich überprüfen, ob das Lebewesen was ich übergeben
bekomme eine Kuh ist:void CheckObject( Lebewesen* vp_Lebewesen )
{if( Kuh* vp_Kuh = dynamic_cast<Kuh*>( vp_Lebewesen ) )
{
cout << "Lebewesen ist eine Kuh" << endl;
}
}Leider bekomme ich den Compilerfehler: Lebewesen ist kein polymorpher Typ.
Wie also kann ich am leichtesten herausbekommen, ob mein Lebewesen
eine Kuh istGrüße
Stephan
-
Hallo,
Hier möchte ich überprüfen, ob das Lebewesen was ich übergeben
bekomme eine Kuh ist:Hier solltest du dich als erstes fragen, warum du das überprüfen möchtest. Ziel der OOP ist es ja gerade solche Fragen durch die Verwendung von virtuellen Methoden unnötig werden zu lassen.
Leider bekomme ich den Compilerfehler: Lebewesen ist kein polymorpher Typ.
Was darauf hindeuted, dass du öffentliche Vererbung falsch einsetzt. Eine öffentliche Basisklasse sollte in der Regel immer ein polymorpher Typ sein, da sonst keine wirkliche ist-ein-Beziehung modelliert wird.
Wie also kann ich am leichtesten herausbekommen, ob mein Lebewesen
eine Kuh istDie technische Antwort: Mach Lebewesen zu einem polymporphen Typ (also zu einem Typ mit mindestens einer virtuellen Methode). Dann funktioniert auch der dynamic_cast.
Sinnvoll ist das was du hier versuchst aber nicht.
-
Hallo,
ich schildere mal mein eigentliches Ziel genauer.
Ich habe verschiedene Objekte gleichen Basistypes aufeinander anwenden.Im theoretischen Beispiel:
Ein anderes Lebewesen wäre zum Beispielein Bauer.
Er hat die Methode melke( Lebewesen* ).
Da die Methode zur Laufzeit ein Lebewesen übertragen bekommt, muss
sie erst einmal überprüfen, ob es eine Kuh ist. Erst dann kann
der Bauer auch melkenWelches Design würdest Du vorschlagen, für mich war das oben beschriebene
am sinnvolsten ?Gruss und Danke
Stephan
-
mach doch eine basisklasse namens MelkbaresLebewesen
-
Könnte ich machen, würde aber nichts an meinem Problem ändern.
Der Melkenmethode wird dann ein Objekt der Klassen
-> Lebewesen->Tier->Vierbeiner->MelkbaresLebewesen-> Kuh übergeben.
Der Parameter ist aber immernoch Lebewesen. Ich müsste also
herausbekommen, ob das Lebewesen ein Melkbares Lebewesen ist.Gruss
-
HumeSikkins schrieb:
Sinnvoll ist das was du hier versuchst aber nicht.
Das verstehe ich nicht. Oder willst du darauf hinaus dass es keinen Sinn macht eine nicht polymorphe Basisklasse zu haben ?
Dass folgende Beispiel funktioniert einwandfrei.#include <iostream> #include <string> #include <vector> class lebewesen { public: lebewesen() {} virtual std::string gettype() = 0; // macht's polymorph }; class Kuh : public lebewesen { public: Kuh():lebewesen() {} virtual std::string gettype() { return "Kuh"; } }; class Schwein : public lebewesen { public: Schwein():lebewesen() {} virtual std::string gettype() { return "Schwein"; } }; void CheckObject( lebewesen* vp_Lebewesen ) { if( vp_Lebewesen->gettype() == "Kuh" ) { std::cout << "Lebewesen ist eine Kuh" << std::endl; } else { std::cout << "Lebewesen ist keine Kuh" << std::endl; } } // eleganter void CheckObject2( lebewesen* vp_Lebewesen ) { if( dynamic_cast<Kuh*>( vp_Lebewesen ) ) { std::cout << "Lebewesen ist eine Kuh" << std::endl; } else { std::cout << "Lebewesen ist keine Kuh" << std::endl; } } int main() { Schwein s; Kuh k; std::vector<lebewesen *> alle; alle.push_back(&s); alle.push_back(&k); std::cout << "using CheckObject" << std::endl; CheckObject(alle[0]); CheckObject(alle[1]); std::cout << "using CheckObject2" << std::endl; CheckObject2(alle[0]); CheckObject2(alle[1]); }
Kurt
-
Hallo
Der Parameter ist aber immernoch Lebewesen. Ich müsste also
herausbekommen, ob das Lebewesen ein Melkbares Lebewesen ist.Dann must du eben den Parametrer so ändern, das nur Klassen mit der Eigenschaft melkbar übergeben werdem können.
Bauer::melke( melkbaresLebewesen* )
bis bald
akari
-
Erst einmal vielen Dank für den Beispielcode Kurt.
Zum Design ist zu sagen, dass ich die Methode zu generisch wie
möglich halten möchte. Also wirklich als Aufrufparamter das Lebewesen*
übergeben möchte.
Ich halte diese Lösung jetzt für optimal, oder übersehe ich dabei etwas ?Grüße
Stephan
-
Stephan1024 schrieb:
Erst einmal vielen Dank für den Beispielcode Kurt.
Zum Design ist zu sagen, dass ich die Methode zu generisch wie
möglich halten möchte. Also wirklich als Aufrufparamter das Lebewesen*
übergeben möchte.
Ich halte diese Lösung jetzt für optimal, oder übersehe ich dabei etwas ?Grüße
StephanDas ist doch Käse.Wenn du in der Methode nen Objekt erwartest dass die "Schnittstelle" eines melkbaren Wesens implementiert warum solltest du dann selber erst prüfen ob es so ist wenn der Compiler das für dich erledigen kann?
Was willst du denn in der melk Methode mit nem Lebewesen das nicht gemolken werden kann anfangen???
Da kannst du ja gleich an alle Methoden nur noch void Pointer übergeben um "die Methoden so generisch wie möglich zu halten"...MfG Spacelord
-
Stephan1024 schrieb:
Ich halte diese Lösung jetzt für optimal, oder übersehe ich dabei etwas ?
Ja. Generizität ist eine feine Sache, aber nur da wo sie Sinn macht.
Wenn du eine Funktion/Methode hast um ein Lebewesen zu melken, was bringt dir die Möglichkeit jegliches Objekt zu übergeben? Du kannst ohnehin nur jene melken die man auch wirklich melken kann. D.h. im Endeffekt musst du erst prüfen ob das Lebewesen melkbar ist oder nicht; wenn nicht, was machst du dann? Richtig, im schlimmsten Fall gar nichts, im besten Fall ein wenig (oder uU viel, Stichwort "Clients") Aufwand betreiben um diese Situation zu behandeln.
Es macht schlicht keinen Sinn ein nichtmelkbares Lebewesen melken zu wollen.Wenn du Flexibilität brauchst dann greif *lol*s Vorschlag auf, siehe akaris Post, dann kannst du sämtliche Kühe, Ziegen, etc melken, musst dich aber nicht fragen was du tun sollst wenn sich ein Elefant in deine Melkmaschine verirrt.
-
Ok, ich würde mir damit den Downcast sparen.
Wenn die Methode so aussehen würde: Melke( MelkbaresLebesen* )
müsste ich bei meinem Objekt des ich übergeben will,
in Beispiel die Kuh nur überprüfen ob sie ein MelkbaresLebesen
ist. Würde mein Programm zur Laufzeit auf einen Menschen als Parameter
stoßen, würde die Methode dann erst gar nicht aufgerufen werden.Richtig ?
-
Hallo
Würde mein Programm zur Laufzeit auf einen Menschen als Parameter
stoßen, würde die Methode dann erst gar nicht aufgerufen werden.Wenn du es richtig machst, wird es nicht mal kompiliert, denn der Compiler merkt dann den Typkonflikt.
Für die Eigenchaft Melkbar ist eventuell auch eine Mehrfachvererbung sinnvoll.bis bald
akari
-
Der Compiler würde es nicht merken, weil erst zur Laufzeit
entschieden wird, welche Objekte aufeinander angewendet werden.
Ich könnte mir ja zur Laufzeit ein Lebewesen aussuchen und möchte es
dem Bauer zum Melken geben. Erst dann kann entscheiden, ob er es annimmt.Gruss
-
Die Bauer::melke Methode sollte nur Melkbare Tiere entgegennehmen. In deinem beispiel würdest du besser vorher entscheiden, um was es sich handelt:
if (MelkbaresTier * melkbaresTier = dynamic_cast<MelkbaresTier *>(tier)) {
bauer.melke (melkbaresTier);
}
else {
...
}