Poloymorphismus + zugriff auf abgeleitete "Klassenvariablen"



  • Original erstellt von Flow_cplus:
    Aber wenn du einen Pointer auf eine Klasse hast, greifst du ganz normal mit Klasse->attribut/Methode() zu. Dabei ist es egal, ob diesttribute von der Mutterklasse ist oder von der abgeleiteten, solange sie als public deklariert sind.

    nicht ganz:

    struct foo {
       virtual void bar () {}
    };
    
    struct faz : foo {
        virtual void baz () {}
    };
    
    int main () {
    
       foo *foo_zeiger = new faz;
       foo_zeiger->bar (); 
    
       //aber wie baz aufrufen? foo_zeiger zeigt auf ein foo, und foo hat keine
       //methode namens baz. also nach faz downcasten:
    
       dynamic_cast<faz&>(*foo).baz();
    }
    

    dynamic cast wirft std::bad_cast wenn sein template argument eine referenz ist, und gibt 0 zurück, wenn in einen zeiger gecastet werden soll.

    zum problem:
    1)
    du kannst wie schon gesagt downcasten, dann caste aber als zeiger, da eine referenz eher eine zusicherung ausdrückt:

    //Beispiele:
    vector <CFeld*> vec;
    vec.push_back(new CStartFeld(10,20)); //whatever
    vec.push_back(new CSpielFeld); //etc.
    
    for (int i = 0; i < vec.size(); ++i) {
       if (CStartFeld *feld = dynamic_cast<CStartFeld*>(vec[i])) {
          //mach was mit einem CStartFeld
       } else if (CSpielFeld *feld = dynamic_cast<CSpielFeld*>(vec[i])) {
          //mach was mit einem CSpielFeld
       }
    }
    
    //Speicher freigeben...
    

    du weißt, dass du downcasten kannst, aber nicht, wann wohin -> als zeiger
    du weißt genau, dass du jetzt downcasten kannst -> referenz (wenn du dich irrst, wird eine ausnahme geworfen)
    zumindest imho ist das gut!

    obiges sieht nach designfehler aus, du solltest dynamic_cast nur in speziellen Fällen verwenden. [Darf jemand anders etwas ausführlicher beschreiben]
    Außerdem willst du downcasten und dann öffentliche Variablen verwenden? Grober Designfehler!
    Also:

    In der Elternklasse getter/setter Methoden (virtuelle natürlich) dazutun.
    Überhaupt: Wenn du auf einen Zeiger auf eine Basisklasse eine Funktion aufrufst, der auf eine abgeleitete Klasse zeigt, die diese Funktion überschreibt, dann musst du die Funktion in der Basisklasse als virtual deklarieren. Ansonsten wird immer die Funktion der Basisklasse aufgerufen.

    Ich hoffe, das war verständlich genug 🙂



  • Original erstellt von Quatschkopp:
    **
    Wenn ich jetzt mit temp->attribut/Methode() auf eine Methode bzw. Attribut zugreifen will, kann ich nur auf die Methoden der Superklasse zugreifen.
    **

    Polymorphismus ist in C++ mit dem Schlüsselwort 'virtual' implementiert.

    struct base {
       virtual void foo () { /*base::foo*/ }
       void bar () { /*base::bar*/ }
       virtual ~base () {} //Destruktoren virtual machen, da sie immer aufgerufen werden (sollten)
    };
    
    struct derived : base {
       void foo /*virtual ist überflüssig*/ () { /*derived::foo*/ }
       void bar () { /*derived::bar*/ } //ist nur eine überdeckung!
    };
    
    int main () {
       base *b = new derived;
       b->foo (); //ruft derived::foo auf! (wegen virtual)
       b->bar (); //ruft base::bar auf (ist ja nicht virtual!)
       delete *b; //wenn der dtor nicht virtual wäre, würde nur base::~base und niemals derived::~derived aufgerufen werden!
    }
    

    **
    @cd9000
    wenn ich das mit dynamic_cast mache kommt folgende Fehlermeldung:
    error C2683: dynamic_cast : 'CFeld' ist kein polymorpher Typ
    feld.h(9) : Siehe Deklaration von 'CFeld'
    Was muss ich machen, damit das funktioniert.

    Danke, Stefan**

    Um dynamic cast zu nutzen, musst du mindestens eine virtuelle Methode deklarieren(auch definieren?) (ein vtable muss angelegt sein, sonst ermittelt dynamic_cast den falschen Typ)

    und nicht vergessen: destruktor der basisklasse virtuell machen!

    [ Dieser Beitrag wurde am 08.05.2003 um 20:31 Uhr von davie editiert. ]

    [ Dieser Beitrag wurde am 08.05.2003 um 20:32 Uhr von davie editiert. ]



  • Ok danke,

    ich hoffe, dass ich es damit hinbekomme. Ansonsten melde ich mich nochmal.

    Viele Grüße

    Stefan



  • Ok, klappt jetzt alles!

    Nur nochmal eine Frage. Ist es nicht doof, wenn ich eine Superklasse habe,mit den virtuellen abstrakten Funktionen. Von der leite ich ca. 5 Klassen ab. Dann muss ich ja, wenn ich die Funktionen nur in einer Klasse brauche, die Fkt. in den anderen Klassen leer implementieren! Oder?

    MFG Stefan



  • virtuell != virtuell abstrakt

    Wenn eine Memberfunktion nur virtuell ist, aber nicht abstrakt, benutzen die abgeleiteten Klassen die Funktion der Basisklasse, solange diese nicht in der abgleiteten Klasse überschrieben wird.



  • Acho,

    ich dachte auch virtuelle Methoden müssen immmer überschrieben werden!
    Ist OK!

    MFG Stefan



  • CFeld braucht auf jeden fall ein virtulen destuktor
    wenn du nämlich so was machst

    CFeld * p = new CStartfeld();
    delete p;
    

    wird nur der dtor von CFeld aufgerufen aber wir haben hier ein CStartfeld objekt



  • Jo, ich habe alle Detruktoren von Klassen, wo ich ableite, virtuell deklariert. 🙂



  • Original erstellt von cd9000:
    Lass das C vor dem Klassennamen weg. Wieso? -> Suchfunktion

    Warum hört nur keiner auf mich? 😞



  • @ cd9000

    sorry, dann muss ich meine ganzen Klassen ändern.
    Habe bei der Suchfunktion nichts gefunden. Sag mir doch mal warum!

    MFG



  • Der Thread liegt im "Rund um..." Forum und nicht hier:
    7 Seiten Diskussion über Klassenprefix


Anmelden zum Antworten