Polymorphie



  • Hallo!
    Angenommen ich habe folgendes Design:

    class CBase
    {
      virtual void MachWas();
    };
    
    class CChild : public CBase
    {
      virtual void MachWas();
    };
    
    // im main()...
    CBase *pBase = new CChild;
    //jetzt kann ich ploymorph rumspielen.
    

    Angenommen ich möchte nun aber CChild mit zusätzlichen Funktionen ausrüsten.
    Dann kann ich mit pBase nicht mehr darauf zugreifen (klar - Basis hat keine Info von Abgeleiteter).
    Ist das dann ein Designfehler, oder ganz normal?

    Gruss Theresa



  • klingt schon ziemlich normal für mich. Man spezialisiert doch nicht, um dann die Basisklasse zu verwenden.

    Ist das wirklich Polymorphie? Müssten dazu nicht zwei Klassen, die sich auf der selben Stufe befinden, MachWas() unterschiedlich implementieren?



  • Ist das wirklich Polymorphie? Müssten dazu nicht zwei Klassen, die sich auf der selben Stufe befinden, MachWas() unterschiedlich implementieren?

    Ja... natürlich - z.B.
    CChild und CChild1....



  • CChild implementiert doch gar nicht. Ist doch immer noch virtual...? 😕



  • Bleibt auch bis ans Ende seiner Tage virtual (auch wenn man virtual nicht explizit hinschreiben würde)...



  • HEZ schrieb:

    CChild implementiert doch gar nicht. Ist doch immer noch virtual...? 😕

    Klar implementiert CChild die Methode (außer es deklariert sie als PUR virtuell). Virtual gibt nicht an, ob die Methode implementiert ist, sondern wann entschieden wird, welche Implementation aufgerufen wird (wenn's da steht, entscheidet sich das erst zur Laufzeit entsprechend des übergebenen Objekts; wenn's fehlt, wird das schon zur Compilezeit entsprechend der angegebenen Klasse festgelegt).



  • @Theresa
    Das ist ganz normal. Eine allgemeine Schnittstelle kann nunmal keine Funktionen beinhalten, die nur auf Objekte einer der abgeleitete Klassen angewendet werden können.
    Ganz im Gegenteil, wenn das so wäre wärs ein Designfehler. 😃

    Ein Beispiel 2D-Elemente:

    Linie und Kreis

    Beide besitzen einen Stift und eine Ebene also wird die allgemeine Schnittstelle hierfür die Funktionen bereitstellen.
    Die Linie besitzt jedoch weder Mittelpunkt noch Radius und der Kreis weder
    Anfangs noch Endpunkt. Also sind die Zugriffsfunktionen für diese Attribute
    nicht Bestandteil der allgemeinen Schnittstelle.
    😉



  • @Mathias,
    wenn ich dich richtig verstanden habe, kann ich dann eine Klasse, wie
    ChildN schon mit weiteren Funktionen ausrüsten.
    Zur Laufzeit erzeuge ich mir dann ein Objekt von CChildN und greife dann (neben einem evtl. vorhanden Basisklassenzeiger) darauf zu.

    Wie siehts denn dann mit einen

    dynamic_cast<ChildN* > pBase
    

    aus?



  • Wenn Du Dir sicher bist dass pBase ein CChild1 ist, darfst Du es auf CChild1 casten und dessen Methoden verwenden.

    Wenn Du ein pBase auf ein CChild1 castest obwohl es eigentlich ein CChild2 ist, gibt dynamic_cast NULL zurück.



  • Wenn es notwendig war den ursprünglichen Typ zu erkennen habe ich bisher immer eine virtuelle Funktion in der Basisklasse deklariert und dann in jeder abgeleiteten Klasse ueberschrieben. Diese liefert fuer jede der abgeleiteten Klasse einen anderen enum-Wert zurueck.
    Dann kann man ganz gezielt casten.

    Wie LordJaxom bereits geschrieben hat, ist ein Cast an dieser Stelle nichts böses. Wenn man z.B. in einem Container mit x unterschiedlichen Arten von 2D-Elementen nur die Kreise über ihre Schnittstelle bearbeiten möchte bleibt einem eigentlich nichts anderes übrig als zu casten.

    Man versucht jedoch wenn möglich die Behandlung einesn Objekttyps an einer Stelle zu konzentrieren, z.B. durch den Einsatz von Entwurfsmustern wie Visitor (Funktionsweise: Man uebergibt dem Kreis, der zu bearbeiten ist über die allgemeine Schnittstelle ein Objekt mit Bearbeitungsinformationen (die wiederum allgemein sind uns somit von allen Objekttypen verarbeitet werden könnten) und der Kreis bearbeitet sich dann selbst. Dadurch fällt der Cast flach und was viel wichtiger ist, wie der Kreis zu bearbeiten ist steht in der Definition des Kreises und nicht irgendwo anders).



  • anscheind ein downcast ist unvermeidbar:

    class Base
    {
      virtual dosomething(){};
    };
    class Derived : public Base
    {
      dosomething();
      dosomethingmore();
    }
    void f1(Base *pb)
    {
       Derived *pd = dynamic_cast<Derived*>pb;
       pd->dosomething();
       pd->dosomethingmore();
    }
    void main()
    {
      Derived *_pd = new Derived();
      f1(_pd);
    }
    

    meisten im aufrufende Funktion gibt man Object von der abgeleitetn Class weiter, in f1() steht object von der BaseClass, hier implizit cast, aber wenn man speziale Methode von der abgeleiteten Class benutzen will, muss man downcast.
    Es ist meisten so.


Anmelden zum Antworten