Vererbung mit einer abstrakten Klasse



  • Hallo Jungs,

    ich komme ja eigentlich von der Vulkaan Insel (Java) und dort ist mir die Geschichte mit der Vererbung eigentlich total klar und auch was die Syntax angeht...

    Leider komme ich jetzt nicht 100% mit der Syntax in C++ nicht ganz klar...

    Also folgendes habe ich jetzt vor:

    Es gibt eine Abstrakte Klasse Boot mit dem Attribut bg (Bootsgewicht), eine Klasse Motorboot mit dem Attribut ml (Motorleistung) und eine Klasse Segelboot mit den Attributen sf (Segelfläche) und wg (Windgeschwindigkeit)... Die Klassen Motorboot und Segelboot sollen natürlich von der Klasse Boot erben und diese realisieren...

    Ich war mir nicht sicher wie man eine Abstrakte Klasse in C++ erstellt, doch im Inet gibt es ja einige Beispiele, leider beinhalten die ganzen Beispiele meistens nur eine Methode in der Klasse und kein Attribut...

    Meine Klasse sieht so aus:

    Boot.h

    class Boot {
    protected:
        int bg;
    
    public:
        virtual double speed() = 0;
        virtual void print() = 0;
    };
    

    Meine beiden anderen Klassen sehen wie folgt aus:

    Motorboot.h

    #include "Boot.h"
    
    class Motorboot: public Boot{
    protected:
        int ml;
    
    public:
        Motorboot();
        Motorboot(int ml, int bg);
    };
    

    Motorboot.cpp

    #include <iostream>
    #include "Motorboot.h"
    
    Motorboot::Motorboot()
    :ml(0)
    {
        bg = 0;
    }
    
    Motorboot::Motorboot(int ml, int bg)
    :ml(ml)
    {
        Boot::bg = bg;
    }
    
    void Boot::print()
    {
    
    }
    
    double Boot::speed()
    {
        return 0;
    }
    

    << ICH WERDE DIE KLASSE SEGELBOOT HIER NICHT REINSTELLEN WEIL ES JA EIGENTLICH ÄQUIVALENT IST >>

    Was mir an dieser Stelle nicht gefällt, ist das ich bei dem Konstruktor von Motorboot das Attribut bg nicht über die Initialisierungsliste initialisieren kann...
    Ich muss es im Block inititialisieren...
    Das muss doch sicher auch anders gehen oder wie ist die gängige Art und Weise wie man das in C++ macht?

    So wenn ich jetzt eine kleine main schreibe und ein Motorboot erzeugen möchte sieht das bei mir so aus:

    main.cpp

    #include <iostream>
    #include "Segelboot.h"
    #include "Motorboot.h"
    
    using namespace std;
    
    int main(int argc, const char * argv[])
    {
        Motorboot mb(250, 1000);
        //Segelboot sb(30, 10, 800);
    
        return 0;
    }
    

    Sobald ich das laufen lasse erhalte ich in Zeile 9 einen Fehler der mir sagt:
    Variable type "Motorboot" is an abstract class

    Wieso ist den jetzt Motorboot abstrakt? :S

    Also ich bin mir sicher der Fehler liegt irgendwie in der Syntax bzw. in der Art wie man das in C++ umsetzt...

    Kann mir Jemand helfen bzw. Tipps geben?

    Danke!



  • wegen dem compiler fehler, du musst die methoden, welche du überschreiben möchtest (bei pur virtuellen methoden ein muss) auch nochmal in der entsprechenden abgeleiteten klasse angeben. (In deinem Beispiel Segelboot)

    Grob vereinfacht dargestellt kannst du dir eine abstrakte c++ classe wie ein interface in JAVA vorstellen.

    Bezogen auf dein beispiel fehlt in der klassen definition fehlen die beiden pure virtual methoden. Und auch die implementation der pur virtual Methoden muss du auf Motorboot::speed bzw. Motorboot::print ändern.

    #include "Boot.h"
    
    class Motorboot: public Boot{
    protected:
        int ml;
    
    public:
        Motorboot();
        Motorboot(int ml, int bg);
        virtual double speed(); // <-- wobei hier das virtual nicht zwingend notwendig ist.
        virtual void print();
    };
    


  • vandread schrieb:

    Was mir an dieser Stelle nicht gefällt, ist das ich bei dem Konstruktor von Motorboot das Attribut bg nicht über die Initialisierungsliste initialisieren kann...

    Die Membervariable bg gehört auch nicht zu Motorboot, sondern zu Boot, damit ist es Aufgabe von Boot, diese zu initialisieren. Das macht man über den Basisklassenkonstruktor (analog zu super in Java):

    Boot::Boot(int bg)
      : bg(bg)
    { }
    
    Motorboot::Motorboot()
      : Boot(0)  // Aufruf des Basisklassenkonstruktors
    {
    }
    

    Sobald ich das laufen lasse erhalte ich in Zeile 9 einen Fehler der mir sagt:
    Variable type "Motorboot" is an abstract class

    Wieso ist den jetzt Motorboot abstrakt? :S

    Weil sie zwei rein-virtuelle Methoden von Boot geerbt hat. Das ist in Java meines Wissens genauso, außer dass man abstract statt = 0 schreibt, wieso wundert dich das denn?

    class Motorboot: public Boot{
    protected:
        int ml;
    
    public:
        Motorboot();
        Motorboot(int ml, int bg);
    
        // Überschreibungen deklarieren
        virtual double speed();
        virtual void print();
    };
    
    // ... und definieren:
    double Motorboot::speed()
    {  return ...; }
    
    void Motorboot::print()
    { ... }
    


  • Okay vielen Dank!

    Der springende Punkt war, das ich die Methoden noch mal in der Header angeben muss...

    Das mit dem Konstruktor habe ich mir auch schon gedacht, doch dann habe ich mir gedacht das ein Konstruktor in einer abstrakten Klasse irgendwie keinen Sinn macht... (in Java gibt es keine Konstruktoren in abstrakten Klassen)

    Vielen Dank (:



  • vandread schrieb:

    (in Java gibt es keine Konstruktoren in abstrakten Klassen)

    Äh doch, soweit ich weiß, schon.



  • Normaler Weise brauchen abstrakte Basisklassen auch keinen Konstruktor,
    da abstrakte Basisklassen normaler Weise keine Attribute besitzen.

    In dem Moment, wo die abstrakte Basisklasse Attribute hat, schreibe ich ja den Implementationsklassen schon irgendwie vor, was sie machen sollen,
    was ja dem Konzept irgendwie widerspricht.

    Desweiteren dürfte der häufigste Zweck abstrakter Klassen in C++ die Definition von Interfaces sein, welche ebensowenig Attribute brauchen...



  • @314159265358979
    ja stimmt... mein fehler...

    @DrakoXP
    wieso sollten sie keine attribute besetitzen?
    ist den nicht eigentlich genau das der sinn einer abstrakten klasse,
    eine vorlage für eine klasse zu sein mit attributen und methoden?
    wenn ich bestimmte methoden implementieren will/soll nutze ich natürlich ein interface



  • Wozu willst du einer erbenden Klasse Attribute aufzwingen, wenn deine Methoden alle abstrakt sind?
    Die Klasse kann deine Methoden doch implementieren wie sie will und wenn Sie die Attribute nicht verwendet, die deine Basis vorgibt, wird Speicher verschwendet.
    Das ist zwar hier nicht so schwerwiegend, aber ich traue dir sowas dann auch bei größeren Klassen zu 😕



  • DrakoXP schrieb:

    Normaler Weise brauchen abstrakte Basisklassen auch keinen Konstruktor,
    da abstrakte Basisklassen normaler Weise keine Attribute besitzen.

    In dem Moment, wo die abstrakte Basisklasse Attribute hat, schreibe ich ja den Implementationsklassen schon irgendwie vor, was sie machen sollen,
    was ja dem Konzept irgendwie widerspricht.

    Abstrakte Klassen haben eigentlich nur mindestens eine abstrakte Methode und können daher nicht instanziiert werden. Das heisst aber nicht, dass sie z.B. keine Invarianten anbieten dürfen. Daher dürfen sie dann auch Attribute haben wofür man dann wiederum einen Ctor anbieten sollte.
    Was Du da beschreibst entspricht eher einem Interface (Vermutlich, weil das was der TO da als 'Boot' bezeichnet bis auf das Attribut und dem fehlenden virtuellen Dtor der C++-Entsprechnung eines Interfaces entspricht).


Anmelden zum Antworten