Zugriffsregelung bei Vererbung



  • Hallo,

    wir haben folgende Aufgabe bekommen:

    Es sollen zwei Klassen erstellt werden.

    CMaschine
    - Tarif_Tag: float
    - Dauer: int
    + CMaschine(TT:float, D:int)
    +Mietpreis():float

    Die zweite Klasse soll von CMaschine abgeleitet werden.

    CKfz
    - Tarif_km: float
    - km: int
    + CKfz(TT:float, D:int, Tkm:float, k:int)
    + Mietpreis():float

    Das ganze ist in UML dargestellt. Dabei sollen die Minuszeichen private- und die Pluszeichen public-Elemente anzeigen.

    Meine CKfz erbt nun die private-Elemente von CMaschine nicht.

    class CKfz : public CMaschine //geht nicht
    class CKfz : protected CMaschine //geht nicht
    class CKfz : private CMaschine //geht nicht
    

    Gibt es irgeneinen Weg die privaten Eigenschaften an die abgeleitet Klasse weiterzugeben oder ist die Aufgabe in der Form nicht lösbar?



  • Tobiashi schrieb:

    Gibt es irgeneinen Weg die privaten Eigenschaften an die abgeleitet Klasse weiterzugeben oder ist die Aufgabe in der Form nicht lösbar?

    Na dann ruf doch mal den Base constructor CMaschine::CMaschine im Member-Initialisierungsbereich des CKfz-Konstruktors auf.



  • Tobiashi schrieb:

    Gibt es irgeneinen Weg die privaten Eigenschaften an die abgeleitet Klasse weiterzugeben oder ist die Aufgabe in der Form nicht lösbar?

    Grundsätzlich:
    Man sollte, wenn möglich, immer eine starke Kopplung vermeiden. Sprich: Man sollte auch in einer Ableitung (die an sich eine starke Kopplung ist) möglichst die Abhängigkeit gering halten.

    Da ich nur wenige C++/CLI Kenntnisse habe, mache ich mal ein C++ Beispiel, mit dem vorher schon erwähnten Konstruktoraufruf.

    class CMaschine
    {
      private:
        float Tarif_Tag;
        int Dauer;
    
      public:
        CMaschine(float TT, int D);
        float Mietpreis(); // Ich nehme mal an: virtual?
    };
    
    class CKfz : public CMaschine
    {
      private:
        float Tarif_km;
        int km;
    
      public:
        // Ich gestalte diesen Konstruktor mal aus...
        CKfz(float TT, int D, float Tkm, int k)
        :   CMaschine(TT, D), // Der Konstruktor ist wiederum öffentlich
            Tarif_km(Tkm),
            km(k)
        {}
    
        float Mietpreis();
    }
    

    Von einer wirklich bescheidenen Namensgebung der Parameter, und der IMHO Unsitte der "C"-Präfixe mal abgesehen: Soll Mietpreis nicht eine virtuelle Methode sein? Und zudem: wie spielen Tarif_Tag und Tarif_km zusammen - wenn die Kfz-Klasse nichts mit der CMaschine gemeinsam hat außer einer (vermutlich) virtuellen Funktion, ist das Klassendesign falsch gewählt.



  • Vielen Dank für die engagierten Antworten!!!

    Also die Mietpreisfunktionen sollen laut Aufgabe folgendes tun:

    CMaschine.Mietpreis:
    Berechnet den Mietpreis einer Maschine anhand Ausleihdauer und Tagestarif.

    CKfz.Mietpreis:
    Berechnet den Mietpreis anhand Ausleihdauer, Tagestarif, gefahrenen Kilometern und km-Tarif.
    Mietpreis=Tarif_Tag*Dauer+Tarif_km*gefahrene km

    Meine (Dank euch lauffähige) Lösung:

    #include <iostream>
    
    using namespace std;
    
    class CMaschine
    {
        private:
        float Tarif_Tag;
        int Dauer;
    
        public:
        CMaschine(){};
        CMaschine(float TT, int D)
        {
            Tarif_Tag=TT;
            Dauer=D;
        }
        float Mietpreis()
        {
            return(Tarif_Tag*Dauer);
        }
    
    };
    
    class CKfz : public CMaschine
    {
    
        private:
        float Tarif_km;
        int km;
        float erg;
    
        public:
        CKfz::CKfz(){}
        CKfz(float TT, int D, float Tkm, int k)
        :   CMaschine(TT, D),
            Tarif_km(Tkm),
            km(k)
        {
            erg=TT*D+Tarif_km*km;
        }
        float Mietpreis()
        {
            return(erg);
        }
    };
    
    int main()
    {
        CKfz kfz(28.0, 1, 0.19, 10);
    
        cout << kfz.Mietpreis() << " Euro" << endl;
    
        return 0;
    }
    

    PS:
    Laut dem Skript, das wir in der Schule bekommen haben, erbt eine Klasse ALLE Eigenschaften und Methoden mit Ausnahme der Konstruktoren und Destruktoren.

    Scheint falsch zu sein, oder?!



  • Tobiashi schrieb:

    Laut dem Skript, das wir in der Schule bekommen haben, erbt eine Klasse ALLE Eigenschaften und Methoden mit Ausnahme der Konstruktoren und Destruktoren.

    Scheint falsch zu sein, oder?!

    Nein. Ist in keiner Weise falsch. Nur das die Zugriffspezifikatoren halt auch berücksicht werden. Und wenn du etwas privat deklarierst ist es für eine abgeleitete Klasse halt nicht zugreifbar (ist aber dennoch ein Teil der Klasse).

    P.S: Man sollte immer gegen die Schnittstelle, nie die Implementierung programmieren. Grundsätzlich mache ich alle Variablen private, und wenn wirklich jemand an die Werte kommen muss, werden halt Getter/Setter-Methoden geschrieben (Die Erlauben wenigstens eine gewisse Kontrolle, die ein direkter Variablenzugriff nicht erlaubt).



  • Dein Lehrer will wahrscheinlich, dass Du in CKfz::Mietpreis() CMaschine::Mietpreis() aufrufst (Ausleihdauer und Tagestarif berechnen), dazu "gefahrenen Kilometern und km-Tarif" addierst und das ganze dann zurückgibst.



  • Aaaah, ok bzw. nicht ok - raffe ich noch nicht.

    Müssten dann nicht die privaten Eigenschaften (im Bsp Tarif_Tag und Dauer) in CKfz als private Elemente zur Verfügung stehen?

    Also würde die Klasse so aussehen, wenn man sie "ausschreibt"???

    class CKfz : public CMaschine
    {
        private:
        float Tarif_Tag; //von CMaschine geerbt
        int Dauer;       //von CMaschine geerbt
        float Tarif_km;
        int km;
    [...]
    

    Dann müsste doch meine Methode Mietpreis aber auf die Eigenschaften zugreifen können, oder? An Tarif_km und km kommt sie ja auch ran...

    Grüße Tobi



  • witte schrieb:

    Dein Lehrer will wahrscheinlich, dass Du in CKfz::Mietpreis() CMaschine::Mietpreis() aufrufst (Ausleihdauer und Tagestarif berechnen), dazu "gefahrenen Kilometern und km-Tarif" addierst und das ganze dann zurückgibst.

    Gute Idee, aber das geht doch auch nur mit der Konstruktion (die wir noch nicht besprochen haben):

    CKfz(float TT, int D, float Tkm, int k)
        :   CMaschine(TT, D),
            Tarif_km(Tkm),
            km(k)
    

    Sonst hat ja die Methode keine Werte zum Rechnen...



  • Tobiashi schrieb:

    Müssten dann nicht die privaten Eigenschaften (im Bsp Tarif_Tag und Dauer) in CKfz als private Elemente zur Verfügung stehen?

    1. Schau dir mal bitte die Erklärung an, die ich kürzlich in einem ähnlichen Fall gegeben hatte.

    2. Wenn der Lehrer nicht besprochen hat wie man Konstruktoren der Basisklasse aufruft, würde die Vorgabe (sofern vom Lehrer stammend) eh nicht funktionieren.

    + CMaschine(TT:float, D:int)

    Als einziger Konstruktor bedeutet das es keinen Standardkonstruktor gibt. Und ohne Initialisierungsliste ist es unmöglich von einer Klasse abzuleiten die keinen solchen besitzt.

    Also hast du entweder irgendwas übersehen, oder die Vorgabe stammt nicht von deinem Lehrer.

    cu André


Anmelden zum Antworten