Hallo zusammen,
wie kann ich herausfinden, von welcher Klasse ein Objekt ist?
Irgendwas im Stile von string getClass(object).
Gruß Mike
Hallo zusammen,
wie kann ich herausfinden, von welcher Klasse ein Objekt ist?
Irgendwas im Stile von string getClass(object).
Gruß Mike
Hallo auch,
wie kann ich herausfinden, von welcher Klasse ein Objekt ist?
Irgendwas im Stile von string getClass(object).
hmm, bei der Schreibweise hab ich erstmal bei java geguckt
unter C++ mit typeid (object) ein type_info-Objekt holen, das dann die Methode name () anbietet.
#include
#include
struct Foo
{
void foo ()
{
printf ("%s\n", typeid (\*this).name ());
printf ("%s\n", abi::\_\_cxa\_demangle (typeid (\*this).name (), 0, 0, NULL);
}
};
Ich bin mir nicht so sicher, inwieweit cxxabi.h überall vorhanden ist …
Der von typeid beschriebene String ist implementierungsabhängig, deswegen habe ich den zweiten Teil hinzugefügt, der das Demangling übernimmt, weil du nicht genau gesagt hast, wofür du das brauchst.
soweit, mfg TLF
wie kann ich herausfinden, von welcher Klasse ein Objekt ist?
Irgendwas im Stile von string getClass(object).
Das Zauberwort heißt „RTTI“ (RunTime Type Information):
#include
class Base { ... };
class D1:Base { ... };
class D2:Base { ... };
int main( void ) {
D1 d1;
D2 d2;
Base\* b = &d1;
if( typeinfo(\*b) == typeinfo(d1) ) {
have\_fun\_with( dynamic\_cast(b) );
} else if( typeinfo(\*b) == typeinfo(d2) ) {
have\_different\_fun\_with( dynamic\_cast(b) );
} else {
// WTF?
}
return 0;
}
dynamic_cast wirft außerdem eine std::bad_cast Exception, wenn der Cast ungültig ist.
In vielen Fällen ist RTTI nicht wirklich nötig und führt nur zu ausgesprochen hässlichem Code.
RTTI und Visual C++
Das Zauberwort heißt „RTTI“ (RunTime Type Information):
Genau Muss aber bei allen Versionen von Visual C++ (falls verwendet) explizit eingeschaltet werden, ausser beim 2005er, da ists standardmäßig eingeschalten.
mfg,
Christoph
PS: Wieso sollte RTTI zu unsauberem Code führen? Ich finds jedenfalls besser als so dämliche COM-Objekte über Typelibs zu definieren - oder wie machst du eine Factory ohne RTTI bzw. Typelibs?
PS: Wieso sollte RTTI zu unsauberem Code führen? Ich finds
jedenfalls besser als so dämliche COM-Objekte über Typelibs zu
definieren - oder wie machst du eine Factory ohne RTTI bzw.
Typelibs?
if( typeid(\*b) == typeid(ClassA) ) {
// ...
} else if( typeid(\*b) == typeid(ClassA) ) {
// ...
} else if( typeid(\*b) == typeid(ClassB) ) {
// ...
} else if( typeid(\*b) == typeid(ClassC) ) {
// ...
} else if( typeid(\*b) == typeid(ClassD) ) {
// ...
} else if( typeid(\*b) == typeid(ClassE) ) {
// ...
} else if( typeid(\*b) == typeid(ClassF) ) {
// ...
} else if( typeid(\*b) == typeid(ClassG) ) {
// ...
} else if( typeid(\*b) == typeid(ClassH) ) {
// ...
.
.
.
} else if( typeid(\*b) == typeid(ClassJF) ) {
// ...
} else if( typeid(\*b) == typeid(ClassJG) ) {
} else {
throw "up";
}
Schön ist das nicht… Man kann damit recht eklige Konstrukte basteln, wenn man es nicht besser weiß oder es drauf anlegt. Ist halt ein Stück von dem Seil zum erschießen, von dem es in C++ ja eine Menge gibt.
Oh ja, wenn man eine Klasse „ClassJH“ in der Hierarchie einfügt, dann muss man alle diese Konstrukte ergänzen. In vielen Fällen ist man da mit ein wenig Polymorphie besser bedient.
PS: Wieso sollte RTTI zu unsauberem Code führen? Ich finds
jedenfalls besser als so dämliche COM-Objekte über Typelibs zu
definieren - oder wie machst du eine Factory ohne RTTI bzw.
Typelibs?if( typeid(*b) == typeid(ClassA) ) {
…Oh ja, wenn man eine Klasse „ClassJH“ in der Hierarchie
einfügt, dann muss man alle diese Konstrukte ergänzen. In
vielen Fällen ist man da mit ein wenig Polymorphie besser
bedient.
Ähem? Du hast schon verstanden, was der eigentliche Sinn von RTTI ist? Wie du schon erwähnt hast: für Polymorphie!
Ein kleiner Beispielcode, der ohne RTTI nicht funktioniert:
class Base {};
class Auto : public Base
{
public:
void fahr();
};
class Flugzeug : public Base
{
public:
void flieg();
};
Base\* ptr = new Auto;
if ( dynamic\_cast(ptr) ) // Wird nicht aufgerufen, da wir ja ein Flugzeug haben
dynamic\_cast(ptr)-\>flieg();
if ( dynamic\_cast(ptr) ) // Geht
dynamic\_cast(ptr)-\>fahr();
Der dynamic_cast kann NUR mit RTTI verwendet werden! Den riesen If-Block, den du verfasst hast find ich relativ seltsam, weiß ja nicht, was du vor hast, aber vielleicht würd dir eine Interface-Klasse mit verschiedenen Implementierungen reichen. in den meisten Fällen reichts, den Basistyp zu kennen, da ich ja mit der Klasse arbeiten will, ohne genau zu wissen, was diese macht. Beispiel: Undo/Redo-Klassen, dort ist mir egal ob Undo jetzt die Textfarbe ändert oder Text wegnimmt, Hauptsache die letzte Aktion wird rückgängig gemacht.
Schön ist das nicht… Man kann damit recht eklige Konstrukte
basteln, wenn man es nicht besser weiß oder es drauf anlegt.
Ist halt ein Stück von dem Seil zum erschießen, von dem es in
C++ ja eine Menge gibt.
Du kannst mit allem und jeder Programmiersprache eklige Konstrukte basteln
mfg,
Christoph
Zitat (wegen w-w-w-Markup):
Base\* ptr = new Auto;
if ( dynamic\_cast(ptr) ) // Wird nicht aufgerufen, da wir ja ein Flugzeug haben
dynamic\_cast(ptr)-\>flieg();
if ( dynamic\_cast(ptr) ) // Geht
dynamic\_cast(ptr)-\>fahr();
Zitat Ende.
Der Sinn von Polymorphie ist eigentlich, dass es ein virtuelles Base::move() gibt, so dass man einfach schreiben kann:
Base\* ptr = new Auto;
ptr-\>move(); // ein Auto fährt, ein Flugzeig fliegt, ...
ohne überall die dynamic_cast-Blöcke erweitern zu müssen, nur weil man ein neues Fahrzeug ins System aufnimmt.
Du kannst mit allem und jeder Programmiersprache eklige
Konstrukte basteln
In manchen Sprachen sind die ekligen Konstrukte aber einfacher zu vermeiden
Base* ptr = new Auto;
ptr->move(); // ein Auto fährt, ein Flugzeig fliegt, …ohne überall die dynamic_cast-Blöcke erweitern zu
müssen, nur weil man ein neues Fahrzeug ins System aufnimmt.
Gut, vielleicht war das Beispiel schlecht gewählt, hab nämlich was anderes gemeint. Das COM-Prinzip läuft eigentlich genauso, nur ist es halt Prozessübergreifend.
Der dynamic_cast ist mit dem QueryInterface() gleich zu setzen. Nehmen wir an, ich hab ein Grundstück. Dieses kann ich per QueryInterface oder dynamic_cast fragen „hast du ein Haus drauf? Wenn ja, gib mir den Pointer zum Haus.“ oder „Hast du ein Gartentor, wenn ja, gib mir den Pointer, damit ich es schließen kann“.
Verstanden, auf was ich eigentlich raus wollte?
Mfg,
Christoph
Gut, vielleicht war das Beispiel schlecht gewählt, hab nämlich
was anderes gemeint. Das COM-Prinzip läuft eigentlich genauso,
nur ist es halt Prozessübergreifend.Der dynamic_cast ist mit dem QueryInterface() gleich zu
setzen. Nehmen wir an, ich hab ein Grundstück. Dieses kann ich
per QueryInterface oder dynamic_cast fragen „hast du ein Haus
drauf? Wenn ja, gib mir den Pointer zum Haus.“ oder „Hast du
ein Gartentor, wenn ja, gib mir den Pointer, damit ich es
schließen kann“.
Wie schön, dass ich mich nie mit COM auseinandersetzen musste
Aber: ich habe um es ganz genau zu nehmen nicht gesagt, dass RTTI von sich aus böse ist, und das wollte ich auch nie. Es ist nur so, dass in vielen Fällen eben doch eher Missbrauch getrieben wird als dass etwas produktives dabei rausfällt. Die Resultate sind dann eben gerne solche lustigen Code-Würmer wie „weiter oben“.
Verstanden, auf was ich eigentlich raus wollte?
Du willst auf Methoden oder Attribute in Unterklassen zugreifen, die in der Basisklasse nicht definiert sind. So weit so klar. Kann sinnvoll sein, muss aber nicht.