Problem mit Polymorphie



  • Hi,
    hier erstmal ein Beispielcode, der das Problem erläutert:

    class foo
    {
    public:
      virtual void speak() {...}
    private:
    
    };
    
    class bar : public foo
    {
    public:
      virtual void speak() {...}
      void run() {...}
    private:
    };
    
    int main()
    {
     foo* test = new bar();
     test->speak(); //funktioniert
     test->run();  // funktioniert nicht
    }
    

    Wieso bekomme ich bei dem Aufruf von run() die Meldung, dass run() kein Member von foo ist? Eigentlich sollte er doch die Version von bar aufrufen. Wie kann ich es machen, dass das ganze funktioniert? Ich will eigentlich keine abstrakte Funktion run() in meiner Basisklasse einfügen, weil das ja nicht der Sinn von Vererbung ist...



  • test ist ein Pointer auf ein foo-Objekt, und wird auch so behandelt. Auch wenn in wirklichkeit ein bar-Objekt dahinter steht.



  • Amateur as Guest schrieb:

    Wieso bekomme ich bei dem Aufruf von run() die Meldung, dass run() kein Member von foo ist? Eigentlich sollte er doch die Version von bar aufrufen. Wie kann ich es machen, dass das ganze funktioniert? Ich will eigentlich keine abstrakte Funktion run() in meiner Basisklasse einfügen, weil das ja nicht der Sinn von Vererbung ist...

    Genau das ist aber der Sinn von Polymorhpie. Foo hat kein Member run(), das siehst Du auf den ersten Blick, der Compiler natürlich erst recht. Wenn so etwas gehen würde, wofür bräuchte man dann "virtual void speak()"? Richtig, garnicht.



  • Willst du es dirty machen, dann caste test auf bar* 👎



  • ...willst Du es sauber machen, dann benutzt Du dynamic_cast und überprüfst, ob der Cast erfolgreich war 👍



  • Hmm, dann hab ich wohl den Sinn hinter der Polymorphie noch nicht verstanden.
    Im Endeffekt muss ich die Polymorphie dann weglassen und ein Objekt von meiner abgeleiteten Klasse erstellen oder? Dann dürfte es funktionieren... Nur wozu brauche ich dann die Polymorphie wenn nicht für so etwas wie ich es oben geschildert habe?



  • Amateur as Guest schrieb:

    ...Nur wozu brauche ich dann die Polymorphie wenn nicht für so etwas wie ich es oben geschildert habe?

    Polymorphie nutzt Du dann, wenn verschiedene Klassen dieselbe Schnittstelle anbieten UND Du nicht zu wissen brauchst, wie das konkrete Objekt diese Schnittstelle implementiert.

    Wenn Du z.B. alle Fahrzeuge "fahren" lassen willst, kannst Du das mittels

    vector<Fahrzeug*> fahrzeuge;
    fahrzeuge.push_back(new Fahrrad);
    fahrzeuge.push_back(new Mofa);
    fahrzeuge.push_back(new LKW);
    
    for(size_t i=0; i<fahrzeuge.size(); ++i) {
       fahrzeuge[i]->fahre();
    }
    
    // .. später delete nicht vergessen
    

    In Deinem Beispiel ist diese Bedingung nicht erfüllt.

    Gruß,

    Simon2.



  • Dummes Lehrbuchbeispiel:

    class Fahrzeug
    {
       public:
        virtual void GibGas();
    }
    
    class Auto: public Fahrzeug
    {
       public:
       virtual void GibGas() //ob du hier das virtual mit anführst ist Geschmackssache
       {
           TrittGaspedal();
       }
       private:
       void TrittGaspedal();
    }
    
    class Moped : public Fahrzeug
    {
     public:
      virtual void GibGas()
      {
         DreheGasgriff();
      }
    private:
      void DreheGasgriff();
    }
    
    int main()
    {
       std::vector<Fahrzeug> Garage;
    
       Auto Mercedes;
       Moped Simson; //ja, ich bin  aus dem Osten :D
    
       //Der Garage ist es egal, was drinsteht
       Garage.push_back(Mercedes);
       Garage.push_back(Simson);
    
       Garage[0].GibGas(); //Fahr den Mercedes raus
       Garage[1].GibGas(); //Fahr das Moped raus
       ...
    }
    

    Grüße,

    Martin

    Edit: @Simon2: Zwei Doofe, ein Gedanke 😃



  • Hmmm,
    so habe ich mir das ja auch gedacht... Aber in deinem Beispiel könnte ich ja z.B. nicht dem LKW eine spezifische Methode verpassen, die meine Fahrzeugschnittstelle nicht besitzt, und diese Methode dann über einen Fahrzeugpointer aufrufen. Sondern um an die Methode zu kommen brauche ich dann entweder nen Cast oder einen LKW Pointer.
    Oder anders gesagt, Polymorphie verwende ich nur dann, wenn ich mehrere Objekte habe, die alle eine Methode verwenden, die auch in meiner Basisklasse vorkommt... Wenn ich eine Funktion benötige, die nicht in meiner Basisklasse vorkommt, verzichte ich auf Polymorphie und verwende ein Objekt meiner abgeleiteten Klasse???



  • Den Downcast sollte man in jedem Fall versuchen zu vermeiden...
    Besser ist, dort wo du auf die Methoden deiner abgeleiteten Klasse zugreifen musst, eine eigene Referenz auf die abgeleitete Klasse zu behalten, und/oder der Basisklasse eine virtuelle Methode "MachDeinZeug()" zu verpassen, und der abgeleiteten Klasse soviel Eigenintelligenz zu spendieren, dass sie selbst weiß, was zu tun ist.
    Das würde auch dem Grundprinzip der Eigenverantwortlichkeit der Objekte entsprechen...

    Grüße,

    Martin



  • Also die sauberste Methode wäre es die Funktion run() in der Basisklasse zu deklarieren. Scheint mir eine allgemeine Funktion zu sein. 😃

    Dein Problem an der Stelle ist nicht die Polymorphie sondern die Definition der Schnittstelle. Wenn du einen Verweis auf die Oberklasse hast, kannst du auch nur über deren Schnittstelle auf das konkrete Objekt zugreifen.

    Erst durch diese Einschränkung wird es möglich Objekte unterschiedlichen Typs über die gleiche Schnittstelle anzusprechen. Ansonsten ergäbe sich bei der von foo abgeleiteten Klasse bar2, die keine Funktion run () besitzt ein kleines Problem....


Anmelden zum Antworten