Vererbung und static_cast Problematik



  • class Base{
    
    int base;
    
    };
    
    class A : public Base{
    
    int a;
    
    };
    
    class B: public Base{
    
    int b;
    
    };
    
    std::list<Base*> data;
    

    die Liste enthält IMMER in abwechselnder Reihenfolge A und B objekte.

    Die einzigste Möglichkeit auf die Daten von A und B zuzugriefen ist ein downcast, was nicht schlimm ist , da die reihenfolge der objekt immst die gleiceh ist, und ich so immer sicher casten kann.

    Aber ich bin immer noch skeptisch, da so downcast von einem schlechten Design sprechen, oder geht es in dem fall nich anders?



  • also erstmal nimm keine static_cast zum down_casten sondern nimm eine dynamic_cast um das richtig objek zu finden:

    if (A* obj=dynamic_cast<A*>(item))
    {
      //code für a
    }
    if (B* obj=dynamic_cast<B*>(item))
    {
      //code für a
    }
    

    das ist die saubere und sichere methode. sie hat allerdings zwei nachteile: a) sie braucht rtti, was aber eigentlich kein echtes problem mehr sein sollte b) es kann streß geben, wenn man versucht das über dll-,so-grenzen hinweg zu nutzen.

    schlechts design ist es nicht, wenn sich das problem nicht anders sinnvoll lösen lässt, was bei down-casts häufiger mal vorkommt.



  • naja dynamic_cast ist sicher wenn ich jedesmal überprüfe ob es wirklich Typ A oder B ist, da aber die Liste immer objekte in abwechsender reihenfolge enhält würd ich eben static_cast nutzen.. aber nur wegen der performance!



  • BorisDieKlinge schrieb:

    ...da aber die Liste immer objekte in abwechsender reihenfolge enhält würd ich eben static_cast nutzen.. aber nur wegen der performance!

    du "optimierst" an der falschen stelle.



  • Wenn man zwei unterschiedliche Objekttypen in einen Container steckt und beim
    spätern Zugriff in JEDEM FalL wieder casten muss, dann ist dies, meines
    Erachtens, (oft) schlechtes Design. Denn offentsichtlich haben die "Items" in
    dem Container keine Gemeinsamkeit und stecken offenbar nur aus Bequemlichkeit
    in einem gemeinsamen Container.
    Aufgrund deiner lückenhaften Beschreibung kann ich natürlich nicht sagen ob
    dein konkretes Problem eine Ausnahme darstellt.



  • @redhead: schau dir mal mein ersten post an.. hätten sie keien gemeinsamkeit würd ich das natürlich nich tun.. die haben gleiceh basisattribute, aber unterscheiden sich eben in extra parametern!

    @publicServiceAnnouncement: Erklär mal...



  • BorisDieKlinge schrieb:

    naja dynamic_cast ist sicher wenn ich jedesmal überprüfe ob es wirklich Typ A oder B ist,

    das macht dynamic_cast mit dem idiom, das ich vorhin gepostet habe, von selber.

    BorisDieKlinge schrieb:

    da aber die Liste immer objekte in abwechsender reihenfolge enhält würd ich eben static_cast nutzen.. aber nur wegen der performance!

    selbst wenn du weißt, was da drin ist, solltest du ein dynamic_cast benutzen. so schrecklich langsam (es sind ein paar if-abfragen...) ist es nicht und wird dich vor bösen überraschungen bewahren, wenn doch mal was mit den daten nicht passt.

    wenn du weißt, was drin ist, dann stellt sich mir die frage: warum nutzt du nicht void* und reinterpret_cast, das ist noch schneller... publicServiceAnnouncement hat schon recht, du optimierst an der falschen stelle.



  • Aber redhead hat recht. Wenn du bei jedem Objekt genau sagen kannst, welchen typ es hat(weil sie immer abwechselnd kommen), dann spricht das schon sehr deutlich dafür, dass du eher 2 listen brauchst.

    Hinzu kommt, dass dir bisher in jedem thread zum Thema casten gesagt wurde, dass casten grundsätzlich auf ein schlechtes Design hinausläuft, also würde ich an deiner Stelle mal überprüfen, ob die leute nicht mit ihrer Vermutung recht haben.

    @ghost wenn man es genau weis, dann ist static_cast die richtige wahl. Es sind halt eben nicht immer nur ein paar ifs.

    Und bei void* mit reinterpret_cast ist implementationsabhängig, was da rauskommt.Mal davon ab, dass man den letzten rest typsicherheit wegwirft.
    Und nur mal btw: static_cast kostet dich ganz genau 0 Takte. zumindest solange du keine virtuelle vererbung nutzt.



  • Du solltest dir nicht beim Design überlegen, ob eine einzelne Operation zuviel Zeit braucht. Wenn das Programm fertig ist und dann nicht schnell genug ist, nimmst du einen Profiler und schaust, wo die Zeit verbraucht wird. Meistens kann man dann durch nen schlaueren Algorithmus viel mehr rausholen, als durch das einsparen von ein paar Casts.



  • BorisDieKlinge schrieb:

    @redhead: schau dir mal mein ersten post an.. hätten sie keien gemeinsamkeit würd ich das natürlich nich tun.. die haben gleiceh basisattribute, aber unterscheiden sich eben in extra parametern!

    Da du in deinem Beispiel jedesmal castest scheint die gemeinsame Basisklasse in
    DEINEM Beipiel ja eben KEINE Rolle zu spielen. Bei Verwendung von virtuellen
    Funktionen und Überschreiben könntest du dir dann nämlich das casten sparen.
    🙄



  • otze schrieb:

    @ghorst wenn man es genau weis, dann ist static_cast die richtige wahl. Es sind halt eben nicht immer nur ein paar ifs.

    was man ungefähr nie mit absoluter sicherheit sagen kann, wenn man nicht vorher mit anderen methoden geklärt hat, was das für ein objekt tatsächlich ist oder eben mit absoluter sicherheit weiß, was da passiert.

    otze schrieb:

    Und bei void* mit reinterpret_cast ist implementationsabhängig, was da rauskommt.Mal davon ab, dass man den letzten rest typsicherheit wegwirft.

    ironie-detektor einschalten.



  • ghorst schrieb:

    oder eben mit absoluter sicherheit weiß, was da passiert.

    Was i.A. der Fall ist wenn man immer ein A und ein B in Folge in den Container packt 😉

    Ich bin auch der Meinung, wenn sicher ist, welches Objekt es ist, kann man static_cast nutzen. Wenn's dann kracht, ist es ein Programmierfehler wie ein Segfault oder Division durch Null.

    Andere Sache Boris:
    Wenn IMMER ein A* und ein B* hintereinander in dem Container liegen, warum nutzt Du dann keinen Container von pair<A*,B*>? Dann kannst Du Dir die Casterei ganz sparen, und die Bedingung "zu einem A gehört ein B" wäre durch die Semantik schon leichter zu erfüllen. Vererbung kannst Du ja dennoch nutzen, um die Gemeinsamkeiten abzubilden, dabei muss die Vererbung nichtmal virtuell sein.



  • LordJaxom schrieb:

    Wenn's dann kracht, ist es ein Programmierfehler wie ein Segfault oder Division durch Null.

    aus meiner sicht ist aber vor allem einer, den man nicht suchen möchte. 😉



  • wie hoch ist die wahrscheinlichkeit das diese fehler auftritt wenn ich die liste so fülle:

    for(int i=1; i< x; i++){
    
     if(i%2)
       LISTE.Add(new A);
     else
       LISTE.Add(new B);
    }
    

    ???



  • ich glaub, so was nennt man dann designfehler. 😉
    bau dir, wie lordjaxom es vorschlug, ein struct, pair oder ähnliches und mach päarchen draus, dann sparst du dir das lästigen casten und erhältst einen sauberen code.



  • das mit dem pair ist ja wunderschön... aber es muss nicht sein das es immer diese reihenfolge ist... es kann auch ein anderes muster sein...das ist das problem...



  • wenn es regelmäßig ist und die periode nicht zu lang, kannst du immernoch eine struct benutzen oder eben für jede klasse eine eigene liste aufziehen. (der verwaltungsaufwand dafür ist auch nicht zu groß.)
    ansonsten hilft dir doch nur ein dynamic_cast.


  • Mod

    otze schrieb:

    Und nur mal btw: static_cast kostet dich ganz genau 0 Takte. zumindest solange du keine virtuelle vererbung nutzt.

    Also immer. Denn mit static_cast sind Downcasts aus einer virtuellen Basisklasse heraus sowieso nicht möglich.


Anmelden zum Antworten