dynamic_cast böse



  • cooky451 schrieb:

    @volkard
    Hast du das schon mal mit etwas komplexeren Dingen ausprobiert?

    Nein. Komplexere Dinge vermeide ich.



  • cooky451 schrieb:

    class Object
    {};
    class MovingObject : virtual public Object
    {};
    class VisibleObject : virtual public Object
    {};
    class PhysicalObject : virtual public Object
    {};
    class ActiveObject : virtual public Object
    {};
    ...
    

    Ich fürchte, dass diese 4 Unterklassen bei mir eine einzige Klassen wären, die die verschiedenen Möglichkeiten einfach durch interne states kodiert. Ich schätze, dass in dem Fall die Klassen, die eine Kombination dieser 4 sind einfach gegenüber den Spezialfällen überwiegen.



  • volkard schrieb:

    Also das da:
    Lastwagen: beweglich, unbewaffnet
    Panzer: beweglich, bewaffnet
    Geschützturm: unbeweglich, bewaffnet

    a) bewegeDich() auf Geschütztürmen tut nichts.
    a1) Geschütztürme haben eine Geschwindigkeit von 0
    c) Lastwagen und Panzer erben von BeweglichesDing
    c1) und getBeweglichesDingPtr(){return this;}
    Ach, mir fiele schon was passendes ein, denke ich.

    Es läuft am Ende darauf hinaus, dass ein Objekt über Schnittstellen verfügt, mit denen es überhaupt nichts zu tun hat. Wenn eine Simulation ausreichend groß wird, werden sicher ziemlich viele verschiedene Eigenschaften von einem anderen Objekt abgefragt werden müssen. Soll für jede einfach das GameObjekt eine neue virtuelle Funktion bekommen?
    Code wird nicht leserlicher und verständlicher, wenn ein unbeweglicher Geschützturm in irgendeiner Form von Moving abgeleitet wird.



  • GorbGorb schrieb:

    Es läuft am Ende darauf hinaus, dass ein Objekt über Schnittstellen verfügt, mit denen es überhaupt nichts zu tun hat. Wenn eine Simulation ausreichend groß wird, werden sicher ziemlich viele verschiedene Eigenschaften von einem anderen Objekt abgefragt werden müssen. Soll für jede einfach das GameObjekt eine neue virtuelle Funktion bekommen?

    Das kommt darauf an, wie der Raum der Objekte aussieht. Ist er sehr strukturiert, da sheißt, gibt es starke Abhängigkeiten zwischen den Eigenschaften, dann lässt sich das Problem mit mehreren abgeleiteten Klassen problemlos erschlagen.

    Anders sieht es wiederum aus, wenn es wenig Struktur gibt, und die Eigenschaften weitestgehend unabhängig voneinander sind. Dann kann man wirklich in ein Problem der exponentiell vielen Klassen laufen. Meistens ist das aber nicht wirklich der Fall. Statistisch dominieren nur wenige Objekttypen, und der Rest sind Spezialfälle und "Was-wäre-wenns" in der Projektplanung.

    Ich habe deinen Link durchgelesen, bis ich dann nach Seite 3 merkte, dass hinter dem Geschwurbel einfach Data-Oriented Programming steht. Die Idee, voneinander unabhängige Daten getrennt zu speichern und zu verarbeiten ist alt. Und im Gegensatz zu dem Artikel ist das kein Gegensätzliches Konzept zur OOP -> Aggregation. Und es funktioniert auch nur in so wenig Spezialfällen, dass man daraus keine allgemeine Regeln ableiten kann. Die Fälle, in denen die Eigenschaftskombinationen unabhängig voneinander sind, sind wenige. Meistens kann zwar Eigenschaft A ohne Eigenschaft B auftreten, aber wenn beide zusammen auftreten, beeinflussen sie sich gegenseitig. Und schon geht das tolle data oriented programming den Bach runter.



  • cooky451 schrieb:

    @volkard
    Hast du das schon mal mit etwas komplexeren Dingen ausprobiert? Bei mir endet das dann so:

    class Object
    {};
    class MovingObject : virtual public Object
    {};
    class VisibleObject : virtual public Object
    {};
    class PhysicalObject : virtual public Object
    {};
    class ActiveObject : virtual public Object
    {};
    ...
    

    Ach und ein aktives, sichtbares, bewegliches Objekt soll dann wiederum von MovingObject, VisibleObject, ActiveObject abgeleitet werden?

    Viel Spaß bei einer unpflegbaren Klassenhirachie. Vielleicht schon einmal das Strategiemuster angeschaut?

    cooky451 schrieb:

    Es geht natürlich auch so, aber wie verhinderst du dann die dynamic_cast Orgie?

    Auch wenn es nicht unbedingt die Ideallösung ist:

    Object * object = ...;
    if(object->MovingStrategie)
      object->move();
    


  • Ich hab etwas ähnliches wie asc:

    Object * object = ...;
    if (object->is(enum_of_types::MOVABLE))
      static_cast<Movable*>(object)->move();
    

    Hält zwar das Interface sauber, aber zufrieden bin ich damit nicht.



  • asc schrieb:

    Ach und ein aktives, sichtbares, bewegliches Objekt soll dann wiederum von MovingObject, VisibleObject, ActiveObject abgeleitet werden?

    Viel Spaß bei einer unpflegbaren Klassenhirachie. Vielleicht schon einmal das Strategiemuster angeschaut?

    Das war gerade ein negativ Beispiel, aber ist ja toll, dass es so gut ankommt. 😉

    otze schrieb:

    Ich fürchte, dass diese 4 Unterklassen bei mir eine einzige Klassen wären, die die verschiedenen Möglichkeiten einfach durch interne states kodiert. Ich schätze, dass in dem Fall die Klassen, die eine Kombination dieser 4 sind einfach gegenüber den Spezialfällen überwiegen.

    Bedenke dass man hierüber auch Dinge wie Sounds, Trigger, Licht, etc. regeln möchte. Das würde das Interface irgendwann halt schon zumüllen.



  • dynamit-karst schrieb:

    Ich hab etwas ähnliches wie asc:

    Ich sehe da schon gravierende Unterschiede im Detail.
    1. Komposition versus Vererbung.
    2. In deinem Fall ist ein Cast nötig.


  • Administrator

    asc schrieb:

    Auch wenn es nicht unbedingt die Ideallösung ist:

    Object * object = ...;
    if(object->MovingStrategie)
      object->move();
    

    Um es ideal zu machen: Null-Objects einführen. Stationäre Objekte haben dann z.B. die Strategie "Stationary". Eine Überprüfung ist dadurch nicht mehr nötig. Die Null-Objects fangen dies ab.

    Grüssli



  • asc schrieb:

    Auch wenn es nicht unbedingt die Ideallösung ist:

    Object * object = ...;
    if(object->MovingStrategie)
      object->move();
    

    Und die Aussage dessen ist wohl dann: Jedes Object könnte move() können. Ob es das wirklich kann, darf man (leider erst) zur Laufzeit abfragen, wenn man will. Die genau Abbildung, welche Klasse was kann, will ich dem Compiler nicht verraten, das würde zu kompliziert.

    Dann kannste auch in der Basisklasse virtual move(){} anbieten, die bei manchen Klassen nichts tut (oder Fehler wirft).

    Falls das Stategy-Pattern verwendet wird, um aktuelle Befehle zu speichern, kannst nach außen wieder versteckt werden mit

    void HottePferd::move(){
      if(this->MovingStrategie)//Diese Zeile fällt mit Draveres Null-Strategie weg
        this->MovingStrategie(this);
    }
    

    Von außen würde ich vermutlich gerne nur move() aufrufen und mich nicht um das Pattern kümmern müssen.


Anmelden zum Antworten