typeid vs dynamic_cast
-
Was ist besser (=schneller) :
class A { public: virtual ~A(){} }; class B:public A { public: virtual ~B(){} }; //... A*a = new B; if(B*b = dynamic_cast<B*>(a)) { }
oder
class A { public: virtual type_info&get_type(){return typeid(*this);} virtual ~A(){} }; class B:public A { public: virtual type_info&get_type(){return typeid(*this);} virtual ~A(){} }; //... A*a = new B; if(typeid(B) == a->get_type()) { }
Was würdet ihr für besser halten? Oder ist das komplet compilerabhängig?
-
Schneller ist vermutlich die zweite Variante (Nachmessen!). Wartbarer/verständlicher eher die erste. Außerdem gibt es noch einige weitere Unterschiede: Wenn Du z.B. noch class C : public B {}; einführst, wird dynamic_cast immer noch feststellen können, ob das Objekt in B* konvertierbar ist; mit typeid geht das nicht.
-
dynamic_cast<> ist prinzipiell vorzuziehen. typeid ist C-Style-Coding und nur für Coder die noch in switch-cases denken. :p Womit dynamic_cast<> halt nichts anfangen kann, sind nicht-polymorphe Objekte, da nur polymorphe Objekte Layout-Informationen haben. D.h. eigentlich, das typeid nur bei nicht-polymorphen Objekten einzusetzen ist, wgebe es da nicht static_cast<> das dieses Problem auch lösen kann.
-
Geht es nicht weder noch?
-
Hallo,
dynamic_cast und typeid sind zwei verschiedene paar Schuhe des selben Herstellers. Wo typeid nur verrät ob ein X vom Typ Y ist, wird dynamic_cast gleich noch aktiv. Es wandelt nebenher ja auch noch um (sofern möglich). D.h. in dem Moment wo man nicht nur wissen will ob X ein Y ist sondern auch gleich noch das X über das Y-Interface referenzieren will, kommt man im Allgemeinen sowieso nicht um einen dynamic_cast rum. Ein static_cast kann schließlich nicht alle legalen down- bzw. cross-casts durchführen.
Bsp:#include <typeinfo> class A {public: virtual ~A();}; class B : public virtual A {}; class C : public virtual A {}; class D : public B, public C {}; void func(A& a) { if (typeid(a) == typeid(D)) { // D& d = static_cast<D&>(a); // error! } // aber: if (D* d = dynamic_cast<D*>(&a)) // ok { //... } } int main() { D d; func(d); }
Insofern ist imo die Frage bereits problematisch.
Wenn ich nun wirklich weiß, dass meine Hierarchie garantiert eingeschränkt ist (z.B. nur einfache Vererbung), ich wirklich einen downcast brauche (weil ich die Basisklasse nicht um eine passende virtuelle Methode ergänzen kann) und an dieser Stelle definitv ein Flaschenhals ist (wenn ich sooft downcasten muss, dann sollte ich wirklich wirklich nochmal über das Design nachdenken), dann würde ich weder typeid noch dynamic_cast verwenden.
Stattdessen würde ich auf einen Integer-Vergleich und einen static_cast setzen.
Im Extremfall kann man dann sogar ganz ohne virtuellen Aufruf auskommen.Nachteil: Reine Capability-Queries sind so nicht einfach möglich. Dafür braucht man dann wieder einen dynamic_cast.