Böser DownCast



  • Original erstellt von HumeSikkins:
    Hilft das?

    Ja, danke.



  • um virtuelle methoden geht es hier nicht

    Huh? Warum nicht?

    man will in den unterklassen noch sachen darueber hinaus

    Man? Wann? Und was für Sachen?

    man kann ja schlecht die vereinigung aller interfaces schon in die basisklasse tun.

    Entschuldige aber ich kann dir nicht folgen. Mir scheint du sprichst über ein spezielles Problem das mir nicht bekannt ist.

    Mal abgesehen davon, dass es viele Situationen gibt in den ein erweitertes Basisklasseninterface sinn macht (Stichwort: Composite), verstehe ich ehrlich gesagt nicht, wieso du von bösen down_casts automatisch zu Unterklassenerweiterung und Visitor kommst.



  • man wuerde ja nicht downcasten wollen, wen alle das gleiche interface haben.
    beim composite gibt es genau 2 dinge zu unterscheiden. selbst das finde ich nicht schoen, aber bei mehr wirds unmoeglich. dann hat man statt der dynamic casts halt isClassA und isClassB und so weiter.



  • man wuerde ja nicht downcasten wollen, wen alle das gleiche interface haben.

    Naja, der downcast tritt ja am häufigsten dort auf wo gerade *keine* ordentlichen Interfaces bzw. Hierarchien existieren. Das ist ja genau der Punkt. Häufig ist ein downcast ein Zeichen dafür, dass man Laufzeit-Polymorphie gar nicht oder nicht gut eingesetzt hat.

    Wie auch immer, imo sollte man erstmal das Naheliegende besprechen, bevor man irgendwelche Design Patterns rauskramt. Besonders wenn es nicht um ein konkretes Problem geht.



  • Wenns um die Unterscheidung verschiedener Ableitungen geht, ist mir bis jetzt noch kein Fall vorgekommen, wo mans nicht auch mit Polymorphie hingekriegt hätte -> mein Beitrag in Deinem anderen Thread.

    Ich kenn das casten nur aus so Fällen, wo man das wissen über den echten Typen eher formal aber nicht wirklich verliert. A la

    class DataSet
    {
      //Basisklasse für die Klassen die für den Output
      //eines Datensatzes zuständig sind 
      class Oput
      {
      public:
         virtual
         bool
        Write(DataSet&)=0;
      }
    };
    
    class Kunde
    :public DataSet
    {
      class Oput
      :Oput
      {
      public:
         virtual
         bool
        Write(DataSet& daset)  //DataSet wird nur wg. der formalen Schnittstelle übergeben
        {                      //ansonten 'weißt' Du, das Kunde::Oput 
                               //nur für Kunden
                               //zuständig ist (dieses Wissen solltest 
                               //Du aber mindestens
                               //mit einem assert oder evtl durch 
                               //geschickte Vergabe von
                               //zugriffsrechten absichern)
           Kunde&
          kunde= static_cast<Kunde&>(daset); //hier reicht schon ein static cast!
    
          //jetzt kannst Du auf die speziellen Schnittstellen des Kunden zugreifen
        }
      }
    };
    

    [ Dieser Beitrag wurde am 08.07.2003 um 22:59 Uhr von kartoffelsack editiert. ]



  • ich hab da in einem projekt z.b. die unterscheidung zwischen pflanze und tier, die beide von lebewesen erben.
    jetzt gibt es 10 verschiedene pflanzen und 10 verschiedene tiere.
    es gibt noch eine klasse, die bestimmte dinge verwaltet, und je nachdem, ob sie eine bestimmte aufgabe erledigen soll, wenn ein tier sie anspricht, oder eine pflanze, soll sie verschiedene interfaces bereitstellen, bzw. ein interface, das sich bei tier oder pflanze verschieden verhält.

    jetzt gibt es die funktion:

    auto_ptr<Interface>
    Verwalterklasse::Interface (Lebewesen *l) {
       if (dynamic_cast<Pflanze*>(l)) return auto_ptr<Interface> (new PflanzenInterface);
       else return auto_ptr<Interface> (new TierInterface);
    }
    

    es gibt einfach niemals mehr als Tier und Pflanze, da ist ein dynamic_cast doch gerade recht. ich weiß, es ist entweder tier oder pflanze. und um dem wesen das richtige interface bereitzustellen, wird der typ unterschieden.
    (ginge normalerweise auch über funktionsüberladung, aber hierfür ist das design zu kompliziert, zumindest komplizierter, als jetzt beschrieben)
    was spricht denn hier dagegen?



  • Der Zweizeiler sieht zwar verlockend einfach aus. Das schlechte daran ist aber imho meist ein grundsätzlicher Designfehler: Du verwirfst das Wissen über die Typen, das Du ja anfangs hast und stellst dann später fest, dass Du's trotzdem wissen muss.
    Das ist so wie wenn Dein Zooverwalter nur mitzählt, wie viele Lebewesen er in seinem Tierpark hat und dann jedesmal beim Futterkaufen den Tierhüter anruft und ihn nachgucken lässt wie viele Löwen und Bananenbäume es jetzt genau sind.



  • Man könnte auch Lebewesen eine virtuelle Funktion LebewesenInterface* createInterface() verpassen, damit wär aber jede Lebewesen-Unterklasse von ihrer korrespondierenden Interface-Klasse abhängig. Also baut man sich, wenn man das nicht will, eine Factory (wie du), und muß dann eben mit dem Type switch leben.



  • ich erstelle aber jedesmal neue lebewesen mit einer passenden factory und weiß so gut wie nichts über ihre typen, vor allem dann nicht, wenn ich das system erweitern will. es gibt gras, baum, hund, katze, etc. und ich kann noch immer mehr dazu machen.
    das einzige, was ich immer sicher weiß, ist, dass es eine Pflanze oder ein Tier ist. Eines von beiden, kein zwischending. Immer.
    und es ist ja auch nur sinnvoll, dem interface der pflanze eine funktion move zu verbieten, oder?



  • Jein. Ich würde in dem Fall sagen, dass ein Lebewesen wissen sollte, ob es sich bewegen kann oder nicht. Dieses Wissen verlagerst Du nach außen in irgendwelche Verwaltungsklassen: Du gugst Dir so ein Lebewesen an gehst dann zu Deinem Verwalter und fragst ihn, was das lebewesen so alles kann. Frag doch das Lebewesen selber! D.h. ich würd mir in Deinem Fall überlegen so ne Art IsMovable-Funktion ins Lebewesen aufzunehmen. Eine Methode Move gäbs aber eben auch in der Basisklasse.



  • das eine pflanze sich nicht bewegt, und das selbst verwalten sollte.
    nun aber wenn ich klassen aus einer dll lade, die nicht von mir ist, darf ich der fremden pflanze die bewegung trotzdem nicht erlauben.
    darauf kommt es mir an.


Anmelden zum Antworten