Ableitung der Klasse

freakontour

Grünschnabel
Hallo zusammen,

ich habe die Klasse GeoFigur, die die Variablen x und y protected darstellt. Die Funktionen drucke() und flaeche() werden public als virtuelle Funktion definiert.
Nun habe ich die Klasse Punkt die die GeoFigur ableitet und die Klassen nutzt. Von der Klasse Punkt soll nun der Kreis abgeleitet werden.
Genau das funktioniert bei mir nicht.

Ich verstehe nicht warum ich die Klasse falsch ableite.

C++:
#include <iostream>
#ifndef M_PI
#define M_PI    3.14159265358979323846f
#endif
using namespace std;

class GeoFigur {

protected:
    int y = 0;
    int x = 0;
public:
    virtual void drucke() = 0;
    virtual float flaeche() = 0;
    virtual ~GeoFigur() {};

};

class Punkt :public GeoFigur {
public:
    Punkt(int i, int j) { x = i; y = j; }
private:
    virtual float flaeche() { return 0; };
    virtual ~Punkt() {};
    void drucke()
    {
        cout << "Punkt:\nP(" << x << "," << y << ") \nund Fläche = 0" << endl;
    }
};

class Kreis : public Punkt{

private:
    float z;
    float flaeche();

    void drucke() {
        cout << "Kreis\n" << "mit P(" << x << "," << y << ",Radius= " << z << "\nund Fläche= " << flaeche() << endl;
    }

public:
    Kreis(int i, int j, float k) { x = i; y = j; z = k; }


};

float Kreis::flaeche() {
    return (M_PI * z * z);
}


int main() {
    GeoFigur* gf = new Punkt(3, 3);
    gf->drucke();
    gf = new Kreis(-1, -1, 4.5f);
    gf->drucke();
    delete gf;
}
 

Anhänge

  • 2020-04-21 19_04_22-Clipboard.png
    2020-04-21 19_04_22-Clipboard.png
    104,9 KB · Aufrufe: 4

Jennesta

Erfahrenes Mitglied
Hallo,

in deinem Code sind einige Dinge, die man verbessern sollte. Ich hoffe ich finde auf die Schnelle alles wichtige.

Punkt 1:
Deine Destruktoren. Diese sollten nicht private sein. Es gibt keinen Grunde diese private zu machen. (Es gibt zwar Spezialfälle in denen man das möchte, kommt aber super selten vor). Was du möchtest ist, dass wenn ein Kreis zerstört wird, dieser den Desktruktor seiner Basisklasse aufruft. Da dieser aber private ist, kann dieser nicht aufgerufen werden und somit wird dieser Fehler erzeugt.
Auf der sicheren Seite (auch wenn nicht zwingend erforderlich) bist du, wenn du dem Kreis ebenfalls einen Destruktor spendierst,

Punkt 2:
Konstruktoren. Die Objekte werden in Reihenfolge ihrer Vererbung konstruiert. D.h. Ein Kreis ruft den Konstruktor des Punkts auf und der den Konstruktor der GeoFigur. In dieser Kette gibt es nun ein Problem bei dir, welches du auf zwei Weisen lösen kannst, wobei ich dir beide Varianten ans Herz legen würde.
Grundsätzlich generiert der Compiler die Standard Konstruktoren (Ebenso wie Standard-Copy und Standard Destruktor), aber nur wenn du selbst keinen definiert hast. Du hast sowohl dem Kreis und dem Punkt keinen Standard-Konstruktor spendiert, weshalb es schlichtweg keinen gibt. Beim Kreis ist es derzeit nicht so schlimm, aber beim Punkt.
Was nun beim Erzeugen eines Kreises passieren würde, es würde versuchen einen Punkt zu konstruieren, findet aber keinen Konstruktor. Das ist das, was die die Fehlermeldung sagt. Das kannst du verhindern, indem du den vorhandenen Konstruktor explizit aufrufst.

C++:
public:
    Kreis(int i, int j, float k) :
        Punkt(x, y) { x = i; y = j; z = k; }

    ~Kreis() {};
};

Die andere Lösung wäre den Standard-Konstruktor zu implementieren, damit dieser falls keiner angegeben wird aufgerufen werden kann.
Nun ist es aber so, dass man das oftmals gar nicht möchte. In diesem Falle würde ich dir trotzdem empfehlen diesen zu implementieren und ihn private zu machen. So kann keiner diesen Aufrufen, er existiert aber und du würdest eine entsprechende Fehlermeldung bekommen.
GeoFigur wird zwar seinen Standardkonstruktor bekommen, du solltest ihn aber trotzdem wie auch den Destruktor hinzufügen. Nur weil der Compiler das automatsich macht, muss man es nicht vernachlässigen.

Punkt 3:
private. Ich glaube du möchtest eigentlich nicht, dass die Funktionen flaeche und drucke private sind. Damit verbietest du allen Nutzern außerhalb den Zugriff auf diese Funktionen. In deinem Codebeispiel funktioniert es nur durch die Vererbung und die virtuellen Funktionen, sodass der Funktionsaufruf der Basisklasse durchgereicht wird. Sowas wie

C++:
Kreis kreis(1, 2, 3);
kreiss.drucke();

wird nicht funktionieren.
Daher die dringende Empfehlung Funktionen auf die man von außen Zugreifen können soll public zu machen.

Punkt 4:
new. Du erzeugst in der main 2x Objekte mit new, rufst aber nur 1x delete auf. Wenn du das erste Objekt nicht mehr benötigst solltest du es dennoch vorher mit delete löschen bevor du den Zeiger nimmst un ihn auf ein neues Objekt zeigen lässt. Denn was hier passiert ist folgendes. Du Erzeugst im Speicher einen Punkt und sagst gf die Speicheradresse.
Nachdem du dann mit drucke die Daten ausgegeben hast erzeugst du ein neues Objekt im Speicher und änderst die Adresse auf die gf zeigt. Das andere Objekt ist im Speicher aber nach wie vor vorhanden, nur dass nun niemand mehr weiß wo es ist. Und wie es zu löschen ist.
Daher solltest du wenn immer du ein Objekt erzeugst es auch löschen. Also in diesem Fall ein
C++:
delete gf;
bevor du dem Zeiger ein neues Objekt zuweist.