abstrakte klassen, abst.funktionen, virtuelle methoden



  • Hallo,
    habe folgende Klassen...

    //Polymorphie , abstrakte Datentypen (Klassen)
    
    #include <iostream>
    #include <conio.h>
    
    using namespace std;
    
    enum COLOR {Red, Green, Blue, Yellow, White, Black, Brown};
    
    class Animal
    {
     private:
             int itsAge;
     public:
            Animal(int);
            virtual ~Animal(){cout<< "Animal-Destruktor..." <<endl;}
    
            virtual int GetAge() const {return itsAge;}
            virtual void SetAge(int age) {itsAge = age;}
            virtual void Sleep() const = 0;
            virtual void Eat() const = 0;
            virtual void Reproduce() const = 0;
            virtual void Move() const = 0;
            virtual void Speak() const = 0;
    };
    Animal::Animal(int age)
    {
     cout<< "Animal-Konstruktor..." <<endl;                   
    }
    //------------------------------------------------------------------------------
    
    class Mammal : public Animal
    {
     public:
          Mammal(int age):Animal(age) {cout<< "Mammal-Konstruktor..." <<endl;}
          virtual ~Mammal () {cout<< "Mammal-Destruktor..." <<endl;}      
    
          virtual void Reproduce() const {cout<< "Mammal-Fortpflanzung..." <<endl;}
    };
    //------------------------------------------------------------------------------
    
    class Fish : public Animal
    {
     public: 
            Fish(int age):Animal(age) {cout<< "Fish-Konstruktor..." <<endl;}      
            virtual ~Fish() {cout<< "Fish-Destruktor..." <<endl;}
    
            virtual void Sleep() const {cout<< "Fisch-schlummert..." <<endl;}
            virtual void Eat() const {cout<< "Fisch-fuettern..." <<endl;}
            virtual void Reproduce() const {cout<< "Fisch-legt Eier..." <<endl;}
            virtual void Move() const {cout<< "Fisch-schwimmt..." <<endl;}
            virtual void Speak() const {}
    };
    //------------------------------------------------------------------------------
    
    class Horse : public Mammal
    {
     protected:
               COLOR itsColor;
     public:
            Horse(int age, COLOR color):Mammal(age), itsColor(color){cout<< "Horse-Konstruktor..." <<endl;}
            virtual ~Horse() {cout<< "Horse-Destruktor..." <<endl;}
    
            virtual void Speak() const {cout<< "Wieher!..." <<endl;}
            virtual COLOR GetItsColor() const {return itsColor;}
            virtual void Sleep() const {cout<< "Pferd schläft..." <<endl;}
            virtual void Eat() const {cout<< "Pferd fuettern..." <<endl;}
            virtual void Move() const {cout<< "Pferd laeuft..." <<endl;}
    };
    //------------------------------------------------------------------------------
    
    class Dog : public Mammal
    {
     protected:
               COLOR itsColor;
     public:
            Dog(int age, COLOR color):Mammal(age), itsColor(color){cout<< "Dog-Konstruktor..." <<endl;}
            virtual ~Dog(){cout<< "Dog-Destruktor..." <<endl;}
    
            virtual void Sleep() const {cout<< "Hund-schlummert..." <<endl;}
            virtual void Eat() const {cout<< "Hund-frisst..." <<endl;}
            virtual void Move() const {cout<< "Hund-laeuft..." <<endl;}
            virtual void Speak() const {cout<< "Wuff!..." <<endl;}
    };
    //------------------------------------------------------------------------------
    
    int main()
    {
        Animal *pAnimal = 0;
        int choice;
        bool fQuit = false;
    
        while(1)
        {
         cout<< "(1)Hund (2)Pferd (3)Fisch (0)Beenden: ";
         cin>> choice;
         switch(choice)
         {
          case 1: pAnimal = new Dog(3, Black);
                  break;
          case 2: pAnimal = new Horse(10, Brown);
                  break;
          case 3: pAnimal = new Fish(122);
                  break;
          default: fQuit = true;
                   break;
         }
         if(fQuit)
           break;
    
         pAnimal -> Speak();
         pAnimal -> Eat();
         pAnimal -> Reproduce();
         pAnimal -> Move();
         pAnimal -> Sleep();
    
         delete pAnimal;            
    
        }//endwhile
    
        getch();
        return 0;    
    }
    

    Wie komme ich bitte schön an meine Age-Variable ran?
    Der Dog-Konstruktor ruft den Mammal-Konstruktor auf und der wiederum ruft den
    Animal-Konstruktor auf und der setzt dann itsAge auf den eingegebenen Wert.
    Wie komme ich denn an den Wert ran? 🙄
    itsAge ist ja privat.
    Was ich nicht verstehe ist: die methode GetAge() wird abgeleitet, weil sie nicht abstrakt ist, aber die Variable itsAge ist doch privat, also kann ich mittels abgeleiteter Klasse nicht auf itsAge zugreifen.



  • hmm, hoffe ich habv das richtig verstanden.
    in der basisklasse (Animal) hast du ja bereits die funktionen get/Set-Age.
    somit müsstes du die doch nicht überschreiben für die abgeleiteten klassen (funktion wird sich doch nicht ändern für die abgeleiteten klassen,oder?)

    und wenn doch, sehe ich hier nur die möglichkeit mittels getAge / setAge die funktionalität zu überschreiben (also nicht direkt auf itsAge zugreifen =(natürlich funktionsaufrufe mehr) )

    just my 2c



  • protected:
        int itsAge;
    

    Das löst dein Problem, protectet ist nach außen wie private nur mit dem unterschied das abgeleitete Klassen auf protectet zugreifen können es is also son zwischending zwischen private und public. Damit kannste auf deine variable zugreifen ohne dich in nem Funktionenwald zu verlaufen.



  • Raven2 schrieb:

    protected:
        int itsAge;
    

    Das löst dein Problem, protectet ist nach außen wie private nur mit dem unterschied das abgeleitete Klassen auf protectet zugreifen können es is also son zwischending zwischen private und public. Damit kannste auf deine variable zugreifen ohne dich in nem Funktionenwald zu verlaufen.

    mMn nicht schön, damit unterläufst du die Kapselung. Das mit den set/get Funktionen der Basis funktioniert doch auch für die Abgeleiteten, solange du sie nicht überschreibst. Die abgeleiteten Klassen rufen Animal::GetAge() auf, und alle sind zufrieden.. 🙂



  • Hi,

    was für mich die Frage anschließt, warum die getter und Setter eigentlich virtual sind ...
    Wenn die Attribute (itsAge) private sind ... welchen Zweck hat dann das aböeiten ?

    Gruß,

    Simon2.



  • Simon2 schrieb:

    ...welchen Zweck hat dann das aböeiten ?...

    Vorsicht gesuchtes Beispiel!
    Angenommen, man rechnet Hundejahre mal sieben und Rattenjahre mal 40, dann könnte es Sinn machen getAge abzuleiten

    int Rat::GetAge() const
    {
        return 40 * Animal::GetAge();
    }
    //...
    int Dog::GetAge() const
    {
        return 7 * Animal::GetAge();
    }
    


  • THX 1138 schrieb:

    ...
    Vorsicht gesuchtes Beispiel!
    ...

    Oha 😮 😮
    Ich würde mich seeeehr hüten vor einer Konstruktion, bei der

    a.setX(a.getX());
    

    zu einer Veränderung von a führt.
    Natürlich kann man setAge() ebenfalls überschreiben, aber insgesamt entspricht das nicht mehr der üblichen getter/setter-Semantik ....

    Es gibt natürlich Konstellationen, in denen innere Attribute in veränderter Form (anderer Typ) nach außen gegeben werden bzw. von außen empfangen werden, aber

    • ich würde dann eher nicht get/set() (als Funktionsnamen) nehmen und
    • ob es sinnvoll ist, die Konvertierung aber nicht die interne Repräsentation den Nachkommen in die Hand zu geben, würde ich auch lange überlegen.

    Aber: "Falsch" ist das natürlich nicht.

    Gruß,

    Simon2.



  • MMn machen getter/setter genau dann Sinn, wenn der Wert noch umgewandelt wird. Ansonsten könnte man gleich eine public Variable nehmen.
    Und natürlich müsste der setter sich auch entsprechend verhalten, also den Wert durch 40 resp. 7 teilen.
    Aber wie gesagt, gesuchtes Beispiel und sowas ist mir auch noch nicht untergekommen. Ich vermeide aber auch protected Variablen wenn es geht, und verwende in abgeleiteten Klassen die getter/setter der Basis.



  • cout<<endl << pAnimal -> GetAge() <<endl;     
    cout<< endl <<pAnimal -> Animal::GetAge() <<endl;
    

    ich bekomme immer den selben wert: 388907
    beim horse und beim dog...
    nur der fish hat 0 🙂



  • Animal::Animal(int age)
    {
     cout<< "Animal-Konstruktor..." <<endl;                  
    }
    

    itsage wird hier nichts zugewiesen 😉


Anmelden zum Antworten