polymorphismus



  • Außerdem sollte der Parameter "const std::string&" sein, sonst geht add("blub") auch weiterhin nicht. Und der Rückgabewert von toString() sollte wohl nicht void sein. Außerdem hoffe ich, dass du den virtuellen Destruktor nur der Lesbarkeit halber gekürzt hast 😉



  • Also ich seh da ein Fehler der gar nichts mit Polymorphy zu tun hat.
    Man kann kein char* zu einer string& casten, (auf welches Object sollte denn Referencirt werden?) Mach aus der Referenze eine Klasse und dann baut der Copykonstruktor dir ein string.



  • Bin mir nicht sicher, denke aber, dass manche Compiler meckern werden, wenn du den Rückgabetyp von toString von const char* nach void umbaust.

    oder was denkst du, wenn du folgendes schreibst:

    void function(IObject* param)
    {
        static char Herribert = param->toString();
    }
    

    Ich denke, dass das nicht geht

    mfg
    Glamdring



  • hubs, das hat Optimizer schon gesagt, naja doppelt hält besser 🤡

    mfg
    Glamdring



  • Mal ne blöde Frage:
    Wieso überhaupt...

    IObject * obj = new FileTree(); 
    // ... und nicht ...
    FileTree * obj = new FileTree();
    

    ???



  • CarstenJ schrieb:

    Mal ne blöde Frage:
    Wieso überhaupt...

    IObject * obj = new FileTree(); 
    // ... und nicht ...
    FileTree * obj = new FileTree();
    

    ???

    Weil FileTree polymorph verwendet werden soll? Stell dir zB mal eine Factory vor.



  • Möglicherweise steck ich nicht tief genug in der Materie drin, also bitte um nähere Erklärung, falls ich etwas falsch verstanden habe.

    Bei der Klasse IObject handelt es sich doch um eine Interface-Klasse.
    Da die Klasse abstrakt ist, muss eben in diesem Fall FileTree die Methode toString() implementieren. Soweit hab ich das verstanden...

    Aber ist...

    IObject * obj = new FileTree();
    

    ...nicht ein Upcast, der im Grunde aussagt, dass FileTree ein IObject ist?



  • CarstenJ schrieb:

    ...nicht ein Upcast, der im Grunde aussagt, dass FileTree ein IObject ist?

    Jo, n upcast. Und die gehen ja 'implizit'.

    nimm zB, folgendes konkretes Beispiel:

    void writeToCout(IObject const& obj)
    {
      cout<<obj.toString();
    }
    
    FileTree f;
    writeToCout(f);
    


  • Ja, aber das wäre doch nur der Fall, wenn die Methode add auch in der Basisklasse deklariert worden wäre?! Wenn das nicht der Fall ist, ist FileTree nicht vom Typ IObject.....und was jetzt eigentlich geplant war, wissen wir ja nicht, weil der sich der Threadersteller nicht dazu geäussert hat.



  • Ja, aber das wäre doch nur der Fall, wenn die Methode add auch in der Basisklasse deklariert worden wäre?! Wenn das nicht der Fall ist, ist FileTree nicht vom Typ IObject.....und was jetzt eigentlich geplant war, wissen wir ja nicht, weil der sich der Threadersteller nicht dazu geäussert hat.

    HÄ??? Besoffen? Was soll der quatsch?



  • Wo ist denn jetzt dein Problem, du Held?



  • Ja, aber das wäre doch nur der Fall, wenn die Methode add auch in der Basisklasse deklariert worden wäre?! Wenn das nicht der Fall ist, ist FileTree nicht vom Typ IObject...

    Ich verstehs auch nicht.

    FileTree ist ein Typ und Typen sind normalerweise nicht "von einem Typ", auch nicht vom Typ IObject. Das ergibt einfach überhaupt keinen Sinn. Was hat die Methode add mit dem Typ zu tun?



  • Dann hab ich das eben falsch ausgedrückt. Was ich meinte bezog sich auf den Code von Shade:

    void writeToCout(IObject const& obj) 
    { 
      cout<<obj.toString(); 
    } 
    
    FileTree f; 
    writeToCout(f);
    

    Die Funktion writeToCout erwartet einen Parameter vom Typ IObject, es wird aber ein Objekt FileTree übergeben. Da FileTree von IObject erbt, hat es die gleichen Schnittstellen wie IObject, welche eben nur anders implementiert werden. Falls was falsch ist, einfach berichtigen...

    Da die Methode add aber in IObject nicht deklariert wurde, haben die beiden Klassen eben nicht die gleiche Schnittstellen......also kann man doch auch kein FileTree übergeben, wenn ein IObject erwartet wird. Oder?



  • CarstenJ schrieb:

    Da die Methode add aber in IObject nicht deklariert wurde, haben die beiden Klassen eben nicht die gleiche Schnittstellen......also kann man doch auch kein FileTree übergeben, wenn ein IObject erwartet wird. Oder?

    zB so:

    void f(IObject& o)
    {
      o.add("muh");
    }
    

    Jo, das geht nicht. Denn IObject hat kein add(). Aber mit toString statt add würde es gehen.

    Ich verstehe deinen Punkt einfach nicht...



  • CarstenJ schrieb:

    Da FileTree von IObject erbt, hat es die gleichen Schnittstellen wie IObject, welche eben nur anders implementiert werden.

    implementiert werden koennen / oft auch nicht anders implementiert werden koennen.
    auszerdem kann die schnittstelle der basisklasse um eigene funktionen erweitert werden.
    wenn du von einer klasse

    class base {
    public:
       virtual void foo() { cout << "base::foo"; }
    };
    

    erbst, dann hat jede abgeleitete klasse eine funktion namens foo, deren implementierung bei bedarf geaendert werden kann (in den abgeleiteten klassen).
    zb

    class derived: public base {
    public:
       void foo () { cout << "derived::foo"; }
    };
    

    die abgeleitete klasse darf jedoch auch ihre eigene, spezialisiertere schnittstelle anbieten:

    class derived2 : public base {
    public:
       void foo () { cout << "derived2::foo"; }
       void bar () { cout << "derived2::bar"; }
    };
    

    jetzt schau dir in ruhe folgenden code an:

    derived2 *d = new derived2;
    d->foo();
    d->bar();
    //alles ok bis jetzt.
    
    base *b = d; //so
    //b ist ein zeiger auf base. d ist vom typ derived2. und
    //weil derived2 von base erbt, ist derived2 ein base.
    //deshalb ist ein zeiger auf ein derived2 (d) auch an einen
    //zeiger auf ein base zuweisbar
    
    //achtung: fuer den compiler zeigt b auf ein base (so ist b ja auch
    //deklariert worden)
    //das heiszt: ueber b kann ich nicht die funktionen aufrufen, die derived2 anbietet
    //wohl aber die gemeinsame funktion foo
    
    b->foo(); //was zur ausgabe "derived2::foo" fuehrt.
    


  • implementiert werden koennen / oft auch nicht anders implementiert werden koennen

    Ich meinte damit, da es eine abstrakte Klasse ist, MÜSSEN die erbenden Klassen das implementieren, sonst wären sie ja auch abstrakt...

    Wie auch immer, jetzt ist soweit alles klar. Danke 😃


Anmelden zum Antworten