Sinnsuche in Vererbung ?



  • Ich versuche mir in c++ die Konzepte von Vererbung näher anzueignen, aber bin jetzt in dem Bereich als Anfänger erstmal mit allem aufeinmal etwas überfordert. Folgender Code als Beispiel für mein Problem:

    #include<iostream>
    
    using namespace std;
    
    class  Transportmittel{
    public:
    	void virtual definiere();
    };
    
    class Auto: public Transportmittel {
    public:
    	void definiere() override;
    
    };
    
    //cpp file: 
    void Transportmittel::definiere(){
    	cout<<"Transportmittel : Mittel zur Fortbewegung von Gütern,Objekten,Personen..."<<endl;
    	}
    
    void Auto::definiere(){
    	cout<<"Auto : Mittel zur Fortbewegung vonPersonen..."<<endl; 
    	} 
    
    int main(){
    Transportmittel blue;
    Auto green;
    blue.definiere();
    green.definiere();
    green.Transportmittel::definiere();
    
    return 0;
    
    }
    

    Ausgabe:

    Transportmittel : Mittel zur Fortbewegung von Gütern,Objekten,Personen...
    Auto : Mittel zur Fortbewegung vonPersonen...
    Transportmittel : Mittel zur Fortbewegung von Gütern,Objekten,Personen...
    

    Mein Problem ist nicht der Sinn und Vorteile von Vererbung in C++ zu verstehen, das ist kein Problem, sondern den Sinn der Schlüsselwörter.
    Damit meine Ich folgendes, man soll virtual benutzen wenn der Compiler eine
    Funktion in der abgeleiteten Klasse überschreiben soll bzw. Sie dort existieren soll , und override sagt dass die Funktion überschrieben wird.
    Es ist aber in dem Code Beispiel vollkommen egal, ob man die Schlüsselwörter
    virtual und ovverride benutzt. Es kommt immer dieselbe Ausgabe. Für den Anfang macht das für mich, wenig Sinn ? Es macht keine Unterschied, ob ich
    das Schlüsselwort virtual benutze oder nicht, der Compiler überschreibt, es trotzdem, wenn Ich override wiederum explicit benutze, also sage überschreibe, dann kann Ich immer noch auf die urprüngliche Funktion zugreifen. Es geht doch auch ohne virtual und override schon vollautomatisch ?



  • int main(){
    
    Auto a;
    Transportmittel* tm = &a;
    tm->definiere();
    }
    

    Und so?



  • Bingo ! Danke !
    Jetzt geht es ohne virtual nicht mehr.

    Verändert override noch zusätzlich etwas oder ist das für den compiler nur von Bedeutung ?

    Transportmittel : Mittel zur Fortbewegung von Gütern,Objekten,Personen...
    Auto : Mittel zur Fortbewegung vonPersonen...
    Transportmittel : Mittel zur Fortbewegung von Gütern,Objekten,Personen...
    Transportmittel : Mittel zur Fortbewegung von Gütern,Objekten,Personen...
    
    class  Transportmittel{
    public:
    	void /*virtual*/ definiere();
    };
    class Auto: public Transportmittel {
    public:
    	void definiere(); //override;
    };
    
    //cpp file: 
    void Transportmittel::definiere(){
    	cout<<"Transportmittel : Mittel zur Fortbewegung von Gütern,Objekten,Personen..."<<endl;
    	}
    
    void Auto::definiere(){
    	cout<<"Auto : Mittel zur Fortbewegung vonPersonen..."<<endl; 
    	} 
    int main(){
    Transportmittel blue;
    Auto green;
    blue.definiere();
    green.definiere();
    green.Transportmittel::definiere();
    
    Auto a; 
    Transportmittel* tm = &a; 
    tm->definiere(); 
    return 0;
    }
    


  • Wenn eine Funktion in der Basis virtual ist, kann das in der abgeleiteten Klasse nicht mehr geändert werden. Virtual ist hier technisch überflüssig. Es wird aber oft dennoch verwendet, um beim Lesen des Codes der abgeleiteten Klasse an die Tatsache zu erinnern. Wird virtual in der Basis entfernt, bleibt dies möglicherweise zunächst unbemerkt. Verwendet man in der abgeleiteten Klasse dagegen override, gäbe es dabei eine Fehlermeldung des Compilers.



  • Danke! , habs verstanden für den Anfang.
    (Die Frage stellt sich ja auch, wenn man merkt, dass die Funktion in der Basisklasse nicht entfernbar ist. Also tatsächlich überschreibbar aus der
    Kindklasse, was auch wieder Sinn ergibt...- egal ob override oder nicht, die
    Kindklasse sollte ja nicht die Dinge der Quelle zerstören können, da das ganze
    auch mit Pointern ablaueft...)
    Aber die Antwort macht Sinn.

    Transportmittel* tm = &a; 
    tm->definiere();
    tm->Transportmittel::definiere();
    
    Transportmittel : Mittel zur Fortbewegung von Gütern,Objekten,Personen...
    

    aus der Kindklasse kann man logischerweise nicht die Funktion der Quellklasse
    auslöschen. ("...override ist technisch überflüssig ... " )



  • override schützt auch von Schreibfehlern, beim Überschreiben von Funktionen in Unterklassen.

    class Auto: public Transportmittel {
    public:
        void Definiere(); //ohne "override" ist das eine neue Funktion
    };
    

    Edit:

    Die Funktion "definiere" wurde hier "versehentlich" falsch geschrieben (Anfangsbuchstabe ist hier "D" anstatt "d"). Mit dem Schlüsselwort "override" würde der Compiler an dieser Stelle einen Fehler melden.



  • Danke



  • temi schrieb:

    void Definiere(); //ohne "override" ist das eine neue Funktion
    

    Du meinst wohl eher:
    ohne "override" weiß man nichts genaues, ohne die Elternklasse zu kennen. Es könnte eine neue Funktion sein, es könnte eine virtuelle Funktion sein...
    Mit override ist sichergestellt, dass es irgendwo in einer der Elternklassen ein virtual void Definiere(); gibt.



  • wob schrieb:

    Du meinst wohl eher:
    ohne "override" weiß man nichts genaues, ohne die Elternklasse zu kennen. Es könnte eine neue Funktion sein, es könnte eine virtuelle Funktion sein...
    Mit override ist sichergestellt, dass es irgendwo in einer der Elternklassen ein virtual void Definiere(); gibt.

    Eigentlich meinte ich schon, was ich geschrieben habe.

    Ohne override erhält die Unterklasse eine neue Funktion mit dem Namen "Definiere". Die in der Basisklasse vorhandene virtuelle Funktion "definiere" wird nicht überschrieben. Mit override erhält man eine Fehlermeldung des Compilers, dass man überschreiben möchte, aber es nicht tut.

    Oder verstehe ich dich falsch?



  • temi schrieb:

    Eigentlich meinte ich schon, was ich geschrieben habe.

    Ohne override erhält die Unterklasse eine neue Funktion mit dem Namen "Definiere". Die in der Basisklasse vorhandene virtuelle Funktion "definiere" wird nicht überschrieben.

    Doch, sie wird auch ohne override überschrieben.

    Das kann man ja leicht testen:

    struct A { 
      virtual void x(){cout<<"Ax\n";}
    };
    struct B : public A {
      void x(){cout<<"Bx\n";}
    };
    int main() {
      A* a = new B();
      a->x();
    }
    

    Es wird hier "Bx" ausgegeben. Auch ohne override. Override macht nur ein Programm ungültig, wenn nicht überschrieben wird. Wenn du aus deinem Programm alle overrides (die an Funktonssignaturen, nicht mögliche Variablen mit demselben Namen) löscht, wird es unverändert weiter funktionieren. Genau wie "final" gibt es "override" auch erst seit C++11.



  • Und jetzt reden wir alle aneinander vorbei.



  • blurbs schrieb:

    Und jetzt reden wir alle aneinander vorbei.

    😃 Scheint so.

    wob: Bitte beachte das die Funktion in der Basisklasse "definiere" (kleines "d") heißt und in der "versehentlich" falsch geschriebenen Funktion in der Unterklasse "Definiere" (großes "D"). Das sind zwei unterschiedliche Funktionen.

    override schützt auch von Schreibfehlern, beim Überschreiben von Funktionen in Unterklassen.



  • temi:
    bitte beachte:

    wob schrieb:

    Du meinst wohl eher:
    ohne "override" weiß man nichts genaues, ohne die Elternklasse zu kennen. Es könnte eine neue Funktion sein, es könnte eine virtuelle Funktion sein...
    Mit override ist sichergestellt, dass es irgendwo in einer der Elternklassen ein virtual void Definiere(); gibt.



  • Ich bin froh, dass ich weiß, was ich gemeint habe. Anderen, die meinen, das ich etwas anderes meinte, sei es gegönnt.



  • Alle wissen, was Du gemeint hast, aber Du hast iwie ignoriert (oder nicht verstanden?), was wob gemeint hat. 😉



  • Ich muss als allererstes sagen, dass ich das kleine/große d/D nicht erkannt hatte. Sozusagen gleich mal den Nutzen von override in der Praxis bestätigt.

    Dennoch halte ich die den Kommentar von Temi
    //ohne "override" ist das eine neue Funktion
    für gefährlich/irreführend, weil er suggeriert, dass man hier durch Weglassen von override ein Programm ändern würde. Ein Kommentar wie

    // mit "override" gibt es einen Compile-Fehler,
    // ohne override wird nicht definiere überschrieben, sondern
    // die neue Funktion Definiere erzeugt
    

    wäre klar gewesen.

    Man sagt ja auch nicht:
    int main() buh! {} // ohne "buh!" wird die Funktion 'main' erstellt
    Ich ging implizit davon aus, dass das Programm auch vor dem Weglassen nicht ill-formed sein sollte (und man sich hier im Forum sowas wie d/D automatisch korrigiert).

    Dann ist jetzt auch hoffentlich klar, was ich gemeint habe.



  • wob schrieb:

    Dennoch halte ich die den Kommentar von Temi
    //ohne "override" ist das eine neue Funktion
    für gefährlich/irreführend, weil er suggeriert, dass man hier durch Weglassen von override ein Programm ändern würde. Ein Kommentar wie

    // mit "override" gibt es einen Compile-Fehler,
    // ohne override wird nicht definiere überschrieben, sondern
    // die neue Funktion Definiere erzeugt
    

    wäre klar gewesen.

    100% Zustimmung. Der Kommentar war, zumindest ohne zusätzliche Erläuterung, irreführend (und auch nicht im dem Sinn gemeint, wie von wob beschrieben).

    Danke für die Korrektur.



  • wob schrieb:

    Ich muss als allererstes sagen, dass ich das kleine/große d/D nicht erkannt hatte. Sozusagen gleich mal den Nutzen von override in der Praxis bestätigt.

    Das ist ja gerade der Witz dabei. Um das überhaupt erkennen zu können, muss man ja zwingend die Elternklasse kennen. Du hast aber ja wie oben schon mal zitiert geschrieben:

    wob schrieb:

    ohne "override" weiß man nichts genaues, ohne die Elternklasse zu kennen. Es könnte eine neue Funktion sein, es könnte eine virtuelle Funktion sein...


Log in to reply