Dynamic und Static Cast? oder einfach nur ein normales Cast?



  • BorisDieKlinge schrieb:

    Aber ok, dann frage ich mal anderes herum, unter welchen umständen muss denn ein dynamic_cast verwendet werden?? Gibt es Designs, wo man da nich drum herum kommt? Bzw. wo es Designtechnisch nicht anders umsetzbar ist?

    Kurzfassung: Nur in absoluten Notfällen.

    Etwas ausführlicher: Wenn in deinem Programm Cast-Ausdrücke (egal welche) auftreten, ist das fast immer ein Zeichen für Design-Fehler. Entweder du kennst den korrekten Typ, dann solltest du auch eine dazu passende Variable verwenden (womit der Cast unnötig wird) oder der tatsächliche Datentyp ist irrelevant, dann nimmst du einen Zeiger auf die Basisklasse und arbeitest mit Polymorphie.

    Der einzige Grund für einen Cast ist imho, die Anforderungen irgendwelcher Bibliotheksfunktionen zu erfüllen, die man nicht beeinflussen kann, wie z.B sowas:

    class thread_user
    {
    public:
      void start_thread()
      {
        AfxBeginThread(thread_func,this);
      }
    
      static UINT thread_func(LPVOID me)
      {
        thread_user* pThis = static_cast<thread_user*>(me);
        ...
      }
    };
    


  • CStoll schrieb:

    Der einzige Grund für einen Cast ist imho, die Anforderungen irgendwelcher Bibliotheksfunktionen zu erfüllen, die man nicht beeinflussen kann

    Hmm. Das ist nur eine Facette. Grundsätzlich gibt es einige Fälle, in denen man nicht sinnvoll Typen konkretisieren kann. Ein Beispiel sind z.B. GUI-Bibliotheken, in denen ein Fenster fast immer eine Controls-Collection besitzt, also irgendeinen Container, der Child-Controls enthält. Angenommen, wir wollen nun alle Buttons auf dieser Form durchlaufen und sie anklicken. Der beste Weg dafür ist folgendes:

    for (Iterator<Control> c = form->controls.begin(); c != form->controls.end(); ++c) {
        Button* b = dynamic_cast<Button*>(c);
        if (b) b->perform_click();
    }
    

    Alles andere (z.B. einen Extra-Container für Buttons zu verwalten) verursacht ein enormes Zusatz-Overhead und ist selten praktisch.



  • und auch schlecht erweiterbar. Da ich die VCL verwende, kenne ich diese Situation recht gut. 🙂



  • Das Beispeil von Konrad, ist ungefähr vergleichbar mit meiner Situation... ist also schwer...



  • Shade Of Mine schrieb:

    Die Frage stellt sich immer: warum B und C auf einen Haufen werfen, wenn man den haufen nachher wieder auftrennen will? (zu deutsch: warum eine list<A*> machen und B und C reinstecken um dann nachher nicht A rauszunehmen sondern wieder nach B und C aufzuteilen? Warum dann nicht gleich eine list<B> und eine list<C>?)

    das ist kein haufen, sondern eine kette. was man zuerst vorne anhängt kann man zuerst hinten wieder abholen. allein das könnte der grund sein, warum boris es so macht, wie er's macht.
    🙂



  • pale dog schrieb:

    das ist kein haufen, sondern eine kette. was man zuerst vorne anhängt kann man zuerst hinten wieder abholen. allein das könnte der grund sein, warum boris es so macht, wie er's macht.
    🙂

    Du hast kein Wort von dem verstanden was ich geschrieben habe. Bitte lies es nochmal.

    Ob es eine liste, ein baum, ein dreieck oder ein bunter Hund ist, ist egal. Worum es geht ist: ich schmeisse die Typinformation zum Fenster hinaus und nachher spring ich dann selber aus dem Fenster um sie wieder einzusammeln.

    Da sollte sich sofort die frage stellen: warum wegschmeissen wenn ich dann den Müll druchsuchen muss um es wieder zu finden? Warum nicht einfach nicht wegschmeissen, dann spar ich mir den müll anzufassen.



  • Oder um es kurz zu machen: Man sollte Cast weitgehend vermeiden (Häufig ist ein Cast ein Anzeichen für falsches Design). Wenn man in einer Liste von polymorphen Objekten ständig casten muss ist das meistens ein fehler im Design der Basisklasse.

    cu André



  • Shade Of Mine schrieb:

    Ob es eine liste, ein baum, ein dreieck oder ein bunter Hund ist, ist egal.

    oder ein bleicher hund?
    wie auch immer, manchmal ist das ganz und gar nicht egal!

    Shade Of Mine schrieb:

    Worum es geht ist: ich schmeisse die Typinformation zum Fenster hinaus und nachher spring ich dann selber aus dem Fenster um sie wieder einzusammeln.
    Da sollte sich sofort die frage stellen: warum wegschmeissen wenn ich dann den Müll druchsuchen muss um es wieder zu finden? Warum nicht einfach nicht wegschmeissen, dann spar ich mir den müll anzufassen.

    der vergleich hinkt. wenn es so wäre, dann würde es kein 'dynamic_cast' geben.
    🙂



  • pale dog schrieb:

    Shade Of Mine schrieb:

    Worum es geht ist: ich schmeisse die Typinformation zum Fenster hinaus und nachher spring ich dann selber aus dem Fenster um sie wieder einzusammeln.
    Da sollte sich sofort die frage stellen: warum wegschmeissen wenn ich dann den Müll druchsuchen muss um es wieder zu finden? Warum nicht einfach nicht wegschmeissen, dann spar ich mir den müll anzufassen.

    der vergleich hinkt. wenn es so wäre, dann würde es kein 'dynamic_cast' geben.
    🙂

    Ich weiß, wenn es nach dir ginge, könnte man C++ komplett abschaffen.

    Und der Punkt ist auch nicht, daß man dynamic_cast komplett weglassen sollte. Aber bevor man es anfasst, sollte man sich sehr genau überlegen, ob es denn wirklich notwendig ist (und in mindestens 99% der Fälle ist es tatsächlich günstiger, die notwendigen Typ-Informationen von vornherein bei der Hand zu haben, anstatt sie mühsam rekonstuieren zu müssen).



  • Konrad Rudolph schrieb:

    [...]
    Angenommen, wir wollen nun alle Buttons auf dieser Form durchlaufen und sie anklicken. Der beste Weg dafür ist folgendes:

    for (Iterator<Control> c = form->controls.begin(); c != form->controls.end(); ++c) {
        Button* b = dynamic_cast<Button*>(c);
        if (b) b->perform_click();
    }
    

    Alles andere (z.B. einen Extra-Container für Buttons zu verwalten) verursacht ein enormes Zusatz-Overhead und ist selten praktisch.

    Ob das der Beste Weg ist, sei mal dahin gestellt. Es ist zumindest ein gangbarer Weg.
    Der Code hat mich direkt an eine andere Situation erinnert, wo ein dynamic_cast sinnvoll ist: das azyklische-Visitor-Pattern benötigt in seiner Implementation ebenfalls einen dynamic_cast, hilft gleichzeitig aber dabei dynamic_casts zu reduzieren 😉



  • wieso mühsam? ist der cast-befehl so aufwendig?

    ich dachte wenn ich in meine std::list<A*> B und C speichere, werden ja die typinfos sicher durch polymorhie mitgespeichert.... und könne so einfach gecastet werden..



  • HumeSikkins schrieb:

    for (Iterator<Control> c = form->controls.begin(); c != form->controls.end(); ++c) {
        Button* b = dynamic_cast<Button*>(c);
        if (b) b->perform_click();
    }
    

    Ob das der Beste Weg ist, sei mal dahin gestellt.

    Jetzt hast Du mich neugierig gemacht. Was wäre denn eine bessere Alternative?



  • CStoll schrieb:

    pale dog schrieb:

    Shade Of Mine schrieb:

    Worum es geht ist: ich schmeisse die Typinformation zum Fenster hinaus und nachher spring ich dann selber aus dem Fenster um sie wieder einzusammeln.
    Da sollte sich sofort die frage stellen: warum wegschmeissen wenn ich dann den Müll druchsuchen muss um es wieder zu finden? Warum nicht einfach nicht wegschmeissen, dann spar ich mir den müll anzufassen.

    der vergleich hinkt. wenn es so wäre, dann würde es kein 'dynamic_cast' geben.
    🙂

    Ich weiß, wenn es nach dir ginge, könnte man C++ komplett abschaffen.

    ach nöööö... dann wär's aber ganz schön langweilig hier. 😉



  • Nicht mühsam für dich, aber mühsam hinter den Kulissen.

    Beantworte doch mal die Frage: Wenn B und C so verschieden sind, daß du sie nicht über ein gemeinsames Interface ansprechen kannst - warum machst du dir dann überhaupt die ühe, sie in einer gemeinsamen list<> unterzubringen? Entweder die Klassen sind ähnlich aufgebaut, dann nimmt man den A-Zeiger und ruft dessen (virtuelle) Methoden auf - oder sie haben nichts gemeinsam, dann verwaltet man sie auch unabhängig voneinander.



  • BorisDieKlinge schrieb:

    wieso mühsam? ist der cast-befehl so aufwendig?

    Ja, dynamic_cast ist aufwendig. Man braucht ab und an dynamic_cast, aber man sollte es vermeiden wenn möglich (Und erst recht sollte man zweimal überlegen es beim Interieren über eine große Liste einzusetzen).

    BorisDieKlinge schrieb:

    ich dachte wenn ich in meine std::list<A*> B und C speichere, werden ja die typinfos sicher durch polymorhie mitgespeichert.... und könne so einfach gecastet werden..

    Leider ist das nicht ganz so einfach. Denn A ist die Basisklasse. B und C wissen natürlich das sie auch ein A sind, aber umgekehrt ist der weg nicht ganz so leicht.

    cu André



  • Hallo

    @ Boris :
    Richtig das geht schon. dynamic_cast ist deshalb verpönt weil es eben zur Laufzeit eine Bedingung auswerten muß. Je nach Implementation der RTTI ist das in mehr oder weniger zusätzlichen Taktschritten erledigt, die nicht gebräucht würden wenn der Basistyp ausreicht. Wenn du kein dynamic_cast oder typeid in deinem Programm verwendest kannst du dem Compiler das RTTI sogar ganz ausstellen.

    bis bald
    akari



  • pale dog schrieb:

    wie auch immer, manchmal ist das ganz und gar nicht egal!

    langsam nervst du.
    welche datenstruktur man verwendet um das zu machen ist sowas von irrelevant für das thema.

    Shade Of Mine schrieb:

    Worum es geht ist: ich schmeisse die Typinformation zum Fenster hinaus und nachher spring ich dann selber aus dem Fenster um sie wieder einzusammeln.
    Da sollte sich sofort die frage stellen: warum wegschmeissen wenn ich dann den Müll druchsuchen muss um es wieder zu finden? Warum nicht einfach nicht wegschmeissen, dann spar ich mir den müll anzufassen.

    der vergleich hinkt. wenn es so wäre, dann würde es kein 'dynamic_cast' geben.
    🙂

    und genau das meine ich: du verstehst es nicht und willst es scheinbar nicht verstehen.

    ich habe lang und breit geschrieben warum man in 99% der fälle keinen dynamic_cast braucht - ich war noch nie in der situation einen dynamic_cast zu brauchen. und da ich denke ich nun schon ein wenig code geschrieben habe und so ziemliche jede person die ich schätze ähnliche erfahrungen gemacht hat, ist es durchaus zulässig zu sagen dass dynamic_cast in 99% der fälle unnötig ist.

    ich habe aber ebenfalls gesagt, dass ausnahmen die regel bestätigen.

    nur weil man etwas nicht dauernd verwendet ist es nicht komplett unnütz. zum beispiel verwende ich feuerlöscher selten. um genau zu sein habe ich noch nie einen verwendet. aber ich würde deshalb nicht so weit gehen sie abzuschaffen.

    denk darüber mal nach.



  • Shade Of Mine schrieb:

    pale dog schrieb:

    wie auch immer, manchmal ist das ganz und gar nicht egal!

    welche datenstruktur man verwendet um das zu machen ist sowas von irrelevant für das thema.

    wieso glaubst du das?
    man kann doch sowas z.b. machen, um die vorteile eine bestimmten datenstruktur zu nutzen (siehe auch Konrad Rudolphs beispiel mit dem controls-container).
    🙂

    es geht ja nicht darum, alle objekte auf einen ungeordneten haufen zu werfen, wie du es so schön beschrieben hast...



  • pale dog schrieb:

    Shade Of Mine schrieb:

    pale dog schrieb:

    wie auch immer, manchmal ist das ganz und gar nicht egal!

    welche datenstruktur man verwendet um das zu machen ist sowas von irrelevant für das thema.

    wieso glaubst du das?
    man kann doch sowas z.b. machen, um die vorteile eine bestimmten datenstruktur zu nutzen (siehe auch Konrad Rudolphs beispiel mit dem controls-container).
    🙂

    Ja, sicher - in der Praxis spielen die Feinheiten einer gegebenen Datenstruktur womöglich eine Rolle, aber um diese Datenstrukturen geht es hier nicht. Hier geht es darum, daß sich jemand nicht die Mühe gemacht hat, ein vernünftiges Design zu entwerfen, und dieses Manko nun versucht, mit einigen Casts auszubügeln (und dafür spielt es dann keine Rolle, ob die Objekte in einer Liste, einem Binärbaum oder in einem Hundehaufen untergebracht sind).

    PS: Und wenn du hier nichts produktives beitragen kannst, solltest du dich lieber in deinen Sandkasten zurückziehen. (Sorry, das mußte jetzt raus)



  • CStoll schrieb:

    PS: Und wenn du hier nichts produktives beitragen kannst, solltest du dich lieber in deinen Sandkasten zurückziehen. (Sorry, das mußte jetzt raus)

    ok, tut mir leid. ich lasse euch jetzt in diesem thread in ruhe.
    (du kannst ja meine postings hier löschen, wenn sie dich stören). 😞


Anmelden zum Antworten