dynamic_cast testen



  • ok, um es kurz zu sagen:
    klar wäre es mir auch lieber, wenn das design dementsprechend wäre, dass man ohne typinfos auskommt.
    ist aber nicht so.
    und ich kann mich auch nicht 100% darauf verlassen, dass ich immer die richtigen typen übergeben bekomme. auch nicht schön.
    ist aber so.
    ich brauche jetzt erstmal eine robuste methode, um sichere downcasts durchzuführen. und dafür ist dynamic_cast geeignet.

    also bitte keine bekehrungen im sinne von "dynamic_cast ist ungeeignet". ich werde es im ersten schritt verwenden müssen. mir ist es lieber, wenn die SW beim kunden etwas langsamer ist, als wenn es kracht.

    also daher nochmals meine ursprüngliche frage, auf die bis jetzt keine antwort kam: welche tests sind nötig, um zu sehen, ob dynamic_cast einwandfrei funktioniert? was wären "härtefälle"? reicht der test, den ich oben präsentiert habe?



  • Ich verstehe immer noch nicht, warum GetTyp() besser als typeid sein sollte. Ich wuerde naemlich den Typ in der vtable hinterlegen oder aehnlich.

    Weiterhin funktioniert die vorgestellte Loesung nur mit Blaettern in der Vererbungshierarchie. dynamic_cast beruecksichtigt auch Zwischenknoten. Deswegen wird wohl dynamic_cast auch langsamer sein als GetType/typeid, aber beide Ansaetze sind sowieso nicht aequivalent.



  • auchabgeleitet schrieb:

    Der Test, ob A von B erbt ist ungefähr so implementiert:

    warum sollte es das sein? dr COmpiler kann doch einfach einen Baum speichern der Pro Typ ienen Knoten hat und dann pro Instanz die ID des passenden Klassenknoten speichern. mit der id findest du dann den passenden Knoten im Baum und upcasten ist dann einfach nur die parents solange traversieren bis in Knoten die richtige ID hat. crosscast ist dann Breitensuche im Baum.


  • Mod

    knivil schrieb:

    Weiterhin funktioniert die vorgestellte Loesung nur mit Blaettern in der Vererbungshierarchie. dynamic_cast beruecksichtigt auch Zwischenknoten.

    und Mehrdeutigkeiten. Die Suche kann also bei einem Fund nicht sofort abgebrochen werden. Die Laufzeit eines cross-Casts hängt damit wesentlich von der Gesamtgröße der Vererbungshierarchie ab.
    Einfache Downcasts gehen nat. schneller. Was nicht hilft, wenn der Cast fehlschlägt (dann musste ja der Algorithmus für den Crosscast erst mal angewendet werden).



  • a_type.name() != typeid(B).name()
    

    Meine Güte, liest hier keiner Alexandrescu? Das funktioniert nicht! Es ist nicht garantiert dass zwei Klassen unterschiedliche " type_info "-Namen haben, und auch nicht dass der Name überhaupt gleich bleibt (in der anderen Implementierung oder auch Version)!



  • Deswegen nimmt man ja auch nicht den String sondern die Id. Stringvergleiche sind unnoetig.



  • Sone schrieb:

    a_type.name() != typeid(B).name()
    

    Meine Güte, liest hier keiner Alexandrescu?

    Viel zu viele Leute lesen Alexandrescu.

    Dir ist schon bewusst, dass das eine Beispielimplementation für dynamic_cast war? Die Compilerhersteller werden schon wsisen, ob sie kompatibel zu sich selbst sind.



  • Ich übersehe wohl was. Wozu braucht man Upcasts und Downcasts?
    Die korrekte Lösung für das hier:

    auchabgeleitet schrieb:

    Basis *b=ListeVonPolymorphenObjekten[x];
    if(b->GetTyp()==eTypA)
    {
     Abgeleitet *a=basis_cast<Abgeleitet*>(b); // bummm schon hier!
     a->EineFunktionVonAbgeleitet();
    }
    

    ist doch wohl sowas in der Art:

    struct Basis{
     virtual void rufDieRichtigeFunktionAuf(){
     }
    };
    struct Abgeleitet{
     void EineFunktionVonAbgeleitet();
     void rufDieRichtigeFunktionAuf(){
      EineFunktionVonAbgeleitet();
     }
    };
    
    ...
    
    Basis *b=ListeVonPolymorphenObjekten[x];
    b->rufDieRichtigeFunktionAuf();
    

    Jetzt, da RTTI angeschaltet ist sollte das doch funktionieren und der Compiler wird sich schon was Schlaues und Optimiertes für die Implementierung überlegen.

    Wenn man das nicht will, weil die abgeleiteten Klassen zu verschieden sind, als dass man für alles eine virtuelle Funktion anlegen will, dann sollte man vielleicht nicht alles von der Basis ableiten und in einen Container stopfen.



  • auchabgeleitet schrieb:

    for (auto a_type = typeid(A); a_type.name() != typeid(B).name();) {
    //                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- das ist richtig lahm
    

    Macht man ja auch nicht. std::type_info (und std::type_index ) ist direkt vergleichbar. Der Vergleich kann z.B. auch mit Integern implementiert werden.

    Ich würde hier nicht zu viel spekulieren, die Performance von RTTI hängt massgeblich von der Compiler-Implementierung ab. Ausserdem hat man meist andere Probleme, wenn man RTTI benötigt.


  • Mod

    nwp3 schrieb:

    Ich übersehe wohl was. Wozu braucht man Upcasts und Downcasts?
    Die korrekte Lösung für das hier:

    auchabgeleitet schrieb:

    Basis *b=ListeVonPolymorphenObjekten[x];
    if(b->GetTyp()==eTypA)
    {
     Abgeleitet *a=basis_cast<Abgeleitet*>(b); // bummm schon hier!
     a->EineFunktionVonAbgeleitet();
    }
    

    ist doch wohl sowas in der Art:

    struct Basis{
     virtual void rufDieRichtigeFunktionAuf(){
     }
    };
    struct Abgeleitet{
     void EineFunktionVonAbgeleitet();
     void rufDieRichtigeFunktionAuf(){
      EineFunktionVonAbgeleitet();
     }
    };
    
    ...
    
    Basis *b=ListeVonPolymorphenObjekten[x];
    b->rufDieRichtigeFunktionAuf();
    

    Jetzt, da RTTI angeschaltet ist sollte das doch funktionieren und der Compiler wird sich schon was Schlaues und Optimiertes für die Implementierung überlegen.

    Wenn man das nicht will, weil die abgeleiteten Klassen zu verschieden sind, als dass man für alles eine virtuelle Funktion anlegen will, dann sollte man vielleicht nicht alles von der Basis ableiten und in einen Container stopfen.

    Das geht sogar ohne RTTI, entspricht aber nicht dem gestellten Problem, als da wäre mit Äpfeln und Birnen umzugehen ohne über Obst zu sprechen.


Anmelden zum Antworten