OOP - Polymorphismus - Fehler im Aufbau/Aufruf meiner Klassen?



  • Hallo zusammen,

    ich arbeite nun seit ca. zwei Tagen mit meinem Buch (Programmentwicklung mit C/C++ und HTML . Bildungsverlag EINS . 4. Auflage . 2009) die C++ Objektorientierung durch. Soweit ist das alles verständlich zumal ich OOP vor einigen Jahren schon mal gelernt habe allerdings in PASCAL. Ich hänge nun beim Thema Polymorphismus. Ich habe mir das Thema im Buch sowie im Netz auf Cplusplus angeschaut und ich denke ich habe es auch verstanden. Bei mir kommt hinzu, das ich immer ein Array für Objekte nutze (nutzen möchte) da dies am häufigsten benötigt wird.

    Ich habe auch einige alternativen ausprobiert, wie z.B.

    Buch B("Programmentwicklung mit C/C++ und HTML");
    ObjektArray[i] = &B;

    durch

    ObjektArray[i] = new Buch("Programmentwicklung mit C/C++ und HTML");

    ersetzt aber alles erfolgslos.

    Compiler sagt: 'class Medium' has no member names 'ZeigeAusleihfrist'

    Ich krieg es echt nicht gelöst. Könntet ihr mir bitte helfen?

    Zunächst einmal mein UML-Klassendiagramm: [IMG]UML-Klassendiagramm[/IMG]

    Folgend mein Code - main.cpp:

    #include <iostream>
    #include <iomanip>
    #include <cstdio>
    #include <string>
    #include <time.h>
    using namespace std;
    #include "Medium.h"
    
    int main(int argc, char *argv[])
    {
        int AnzahlObjekte = 5;
        int i = 0;
        int iEingabe;
    
        cout << "- Erzeuge Objekt-Array: ";
        Medium *ObjektArray[AnzahlObjekte];
        cout << "abgeschlossen.";
    
        cout << endl << "- Initialisierung von medien: " << endl;
        cout << "\t-> Erzeuge Printmedium - Buch: ";
        ObjektArray[i] = new Buch("Programmentwicklung mit C/C++ und HTML");
        cout << "abgeschlossen.";
        i++;
    
        for (i = 0; i < AnzahlObjekte; i++){
            //cout << endl << endl << ObjektArray[i]->ZeigeMediumkategorie();
            //cout << endl << ObjektArray[i]->ZeigeMediumtyp();
            //cout << endl << ObjektArray[i]->ZeigeMediumname();
            //cout << endl << ObjektArray[i]->ZeigeAusleihstatus();
            //cout << endl << ObjektArray[i]->ZeigeAusleihdatum();
            cout << endl << ObjektArray[i]->COUT_Ausleihfrist();
        }
    
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

    Medium.h:

    #ifndef MediumH
    #define MediumH
    using namespace std;
    #include <string>
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    class Medium {
          private:
                     int Mediumid;
                     string Mediumkategorie;
                     string Mediumtyp;
                     string Mediumname;
                     string Ausleihstatus;
                     string Ausleihdatum;
          public:
                     static int Laufende_Nummer;
    
                     void SetzeMediumid();
                     int ZeigeMediumid();
                     void SetzeMediumkategorie(string);
                     string ZeigeMediumkategorie();
                     void SetzeMediumtyp(string);
                     string ZeigeMediumtyp();
                     void SetzeMediumname(string);
                     string ZeigeMediumname();
                     void SetzeAusleihstatus(string);
                     string ZeigeAusleihstatus();
                     void SetzeAusleihdatum(string);
                     string ZeigeAusleihdatum();
    
                     string BerechneRueckgabe(int);
    
                            Medium();
                            ~Medium();
    };
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    class Printmedium : public Medium {
          public:
                    virtual int ZeigeAusleihfrist(void)=0;
                    Printmedium();
                    ~Printmedium();
    };
    class Buch : public Printmedium {
          private:
                    int Ausleihfrist;
          public:
                    void SetzeAusleihfrist(int);
                    int ZeigeAusleihfrist(void);
    
                        Buch(string);
                        ~Buch();
    };
    class Zeitschrift : public Printmedium {
          private:
                    int Ausleihfrist;
          public:
                    void SetzeAusleihfrist(int);
                    int ZeigeAusleihfrist(void);
    
                        Zeitschrift(string);
                        ~Zeitschrift();
    };
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    class Softwaremedium : public Medium {
          private:
                    int Ausleihfrist;
          public:       
                     void SetzeAusleihfrist(int);
                     int ZeigeAusleihfrist();                 
    
                         Softwaremedium();
                         ~Softwaremedium();
    };
    class Video : public Softwaremedium {
          public:            
                    Video(string);
                    ~Video();
    };
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    class SonstigesMedium : public Medium {
          private:
                    int Ausleihfrist;
          public:    
                     void SetzeAusleihfrist(int);
                     int ZeigeAusleihfrist(); 
    
                         SonstigesMedium();
                         ~SonstigesMedium();
    };
    class CD : public SonstigesMedium {
          public:         
                    CD(string);
                    ~CD();
    };
    class DVD : public SonstigesMedium {
          public:         
                    DVD(string);
                    ~DVD();
    };
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #endif
    

    Funktionen.cpp:

    #include <cstdlib>
    #include <iostream>
    using namespace std;
    #include "Medium.h"
    
    int Medium::Laufende_Nummer = 0;
    
    Medium::Medium(){
    }
    
    Medium::~Medium(){
    }
    
    void Medium::SetzeMediumid(){
         Mediumid = Laufende_Nummer;
         Laufende_Nummer++;
    }
    
    int Medium::ZeigeMediumid(){
            return Mediumid;
    }
    
    void Medium::SetzeMediumkategorie(string Kategorie){
         Mediumkategorie = Kategorie;
    }
    
    string Medium::ZeigeMediumkategorie(){
            return Mediumkategorie;
    }
    
    void Medium::SetzeMediumtyp(string Typ){
         Mediumtyp = Typ;
    }
    
    string Medium::ZeigeMediumtyp(){
            return Mediumtyp;
    }
    
    void Medium::SetzeMediumname(string Name){
         Mediumname = Name;
    }
    
    string Medium::ZeigeMediumname(){
            return Mediumname;
    }
    
    void Medium::SetzeAusleihstatus(string Status){
         Ausleihstatus = Status;
    }
    
    string Medium::ZeigeAusleihstatus(){
            return Ausleihstatus;
    }
    
    void Medium::SetzeAusleihdatum(string Datum){
         Ausleihdatum = Datum;
    }
    
    string Medium::ZeigeAusleihdatum(){
            return Ausleihdatum;
    }
    
    string Medium::BerechneRueckgabe(int Days){
        time_t now = time(NULL);
        struct tm* tm = localtime(&now);
        tm->tm_mday += Days;
        time_t later = mktime(tm);
        return asctime(tm);
    }
    
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Printmedium::Printmedium(){
    }
    
    Printmedium::~Printmedium(){
    }
    
    void Buch::SetzeAusleihfrist(int Frist){
         Ausleihfrist = Frist;
    }
    
    int Buch::ZeigeAusleihfrist(){
            return Ausleihfrist;
    }
    
    Buch::Buch(string Name){
          SetzeMediumid();
          SetzeMediumkategorie("Printmedium");
          SetzeMediumtyp("Buch");
          SetzeMediumname(Name);
          SetzeAusleihstatus("nicht Ausgeliehen");
          SetzeAusleihdatum(" ");
          SetzeAusleihfrist(4);
    }
    
    Buch::~Buch(){
    }
    
    void Zeitschrift::SetzeAusleihfrist(int Frist){
         Ausleihfrist = Frist;
    }
    
    int Zeitschrift::ZeigeAusleihfrist(){
            return Ausleihfrist;
    }
    
    Zeitschrift::Zeitschrift(string Name){
          SetzeMediumid();
          SetzeMediumkategorie("Printmedium");
          SetzeMediumtyp("Zeitschrift");
          SetzeMediumname(Name);
          SetzeAusleihstatus("nicht Ausgeliehen");
          SetzeAusleihdatum(" ");
          SetzeAusleihfrist(1);
    }
    
    Zeitschrift::~Zeitschrift(){
    }
    
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    Softwaremedium::Softwaremedium(){
                    SetzeAusleihfrist(2);
    }
    
    Softwaremedium::~Softwaremedium(){
    }
    
    void Softwaremedium::SetzeAusleihfrist(int Frist){
         Ausleihfrist = Frist;
    }
    
    int Softwaremedium::ZeigeAusleihfrist(){
            return Ausleihfrist;
    }
    
    Video::Video(string Name){
          SetzeMediumid();
          SetzeMediumkategorie("Softwaremedium");
          SetzeMediumtyp("Video");
          SetzeMediumname(Name);
          SetzeAusleihstatus("nicht Ausgeliehen");
          SetzeAusleihdatum(" ");
    }
    
    Video::~Video(){
    }
    
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    SonstigesMedium::SonstigesMedium(){
                    SetzeAusleihfrist(2);
    }
    
    SonstigesMedium::~SonstigesMedium(){
    }
    
    void SonstigesMedium::SetzeAusleihfrist(int Frist){
         Ausleihfrist = Frist;
    }
    
    int SonstigesMedium::ZeigeAusleihfrist(){
            return Ausleihfrist;
    }
    
    CD::CD(string Name){
          SetzeMediumid();
          SetzeMediumkategorie("SonstigesMedium");
          SetzeMediumtyp("CD");
          SetzeMediumname(Name);
          SetzeAusleihstatus("nicht ausgeliehen");
          SetzeAusleihdatum(" ");
    }
    
    CD::~CD(){
    }
    
    DVD::DVD(string Name){
          SetzeMediumid();
          SetzeMediumkategorie("SonstigesMedium");
          SetzeMediumtyp("DVD");
          SetzeMediumname(Name);
          SetzeAusleihstatus("nicht ausgeliehen");
          SetzeAusleihdatum(" ");
    }
    
    DVD::~DVD(){
    }
    


  • Yaerox schrieb:

    Programmentwicklung mit C/C++ und HTML

    lol. gibts denn gar keine grenzen mehr?



  • virtual muss in Medium, nicht in die anderen Klassen...



  • volkard schrieb:

    Yaerox schrieb:

    Programmentwicklung mit C/C++ und HTML

    lol. gibts denn gar keine grenzen mehr?

    Der Name ist der Name des Buches ^^ Ich kann da nichts für, haben es in der Schule vorgeschrieben bekommen ^^

    Nathan schrieb:

    virtual muss in Medium, nicht in die anderen Klassen...

    Ja, vielen Dank, ich hab es grad ebend selbst hinbekommen ohne zu sehen das hier schon so fix eine Antwort war.

    Vielen vielen Dank 🙂



  • Nathan schrieb:

    virtual muss in Medium, nicht in die anderen Klassen...

    I wo! Solange es keine delete im Code hat ...



  • Doch.
    Wenn Memberfunktionen überschrieben werden sollen, müssen die in der Basisklasse virtual sein.



  • Ach so, ich dachte das bezieht sich auf auf den Destruktor, aber das war eine allgemeine Aussage.



  • Nathan schrieb:

    Wenn Memberfunktionen überschrieben werden sollen, müssen die in der Basisklasse virtual sein.

    Nö. Nur wenn sie über einen Basisklassenzeiger bzw. -referenz aufgerufen werden.



  • MFK schrieb:

    Nathan schrieb:

    Wenn Memberfunktionen überschrieben werden sollen, müssen die in der Basisklasse virtual sein.

    Nö. Nur wenn sie über einen Basisklassenzeiger bzw. -referenz aufgerufen werden.

    Müssen tut man in C++ gar nix.



  • Mein Gott seid ihr kleinlich!
    Der TE will Polymorphie, also muss er virtual verwenden. Punkt.
    Schon mal etwas von Kontext abhängigen Sätzen gehört?



  • Nathan schrieb:

    Mein Gott seid ihr kleinlich!
    Der TE will Polymorphie, also muss er virtual verwenden. Punkt.

    Polymorphismus könnte man auch ganz anderes erreichen.

    Nathan schrieb:

    Schon mal etwas von Kontext abhängigen Sätzen gehört?

    Wenn Du aber den Kontext zerkloppst und absolute allgemeingültige Aussagen daras machst, mit "Punkt." muss man einfach widersprechen.

    Doch.
    Wenn Memberfunktionen überschrieben werden sollen, müssen die in der Basisklasse virtual sein.

    Oh. Allgemeingültige Aussage. Kein Bezug zum Medienverleih, sondern man muss immer.



  • #include <iostream>
    
    class Base
    {
    public:
        void print()
        {
            std::cout<<"Base\n";
        }
    };
    
    class Derived : public Base
    {
    public:
        void print()
        {
            std::cout<<"Derived\n";
        }
    };
    
    int main ()
    {
        Base* o = new Derived;
        o->print(); // wird "Base" ausgeben
        delete o;
    }
    

    In diesem Fall wird immer Base::print aufgerufen, weil o ein Zeiger auf ein Objekt des Typs Base zeigt und nicht weiß, dass man die Funktion überschreiben will.
    Das muss man explicit durch virtual kennzeichnen.

    #include <iostream>
    
    class Base
    {
    public:
        virtual void print()
        {
            std::cout<<"Base\n";
        }
    };
    
    class Derived : public Base
    {
    public:
        virtual void print()
        {
            std::cout<<"Derived\n";
        }
    };
    
    int main ()
    {
        Base* o1 = new Derived;
        Base* o2 = new Base;
        o1->print(); // wird "Derived" ausgeben
        o2->print(); // wird "Base" ausgeben
        delete o1;
        delete o2;
    }
    

    Hierbei wird dann immer die Funktion aufgerufen, die zum entsprechenden Typ gehört.

    Die Fehlermeldung besagt aber nur, dass es Medium::ZeigeAusleiheFrist nicht gibt. Bei den abgeleiteten Klassen hast du die Funktion erstellt, aber bei Medium nicht.



  • volkard schrieb:

    Nathan schrieb:

    Schon mal etwas von Kontext abhängigen Sätzen gehört?

    Wenn Du aber den Kontext zerkloppst und absolute allgemeingültige Aussagen daras machst, mit "Punkt." muss man einfach widersprechen.

    Doch.
    Wenn Memberfunktionen überschrieben werden sollen, müssen die in der Basisklasse virtual sein.

    Oh. Allgemeingültige Aussage. Kein Bezug zum Medienverleih, sondern man muss immer.

    Ich zerkloppe den Kontext?
    Meine Aussage mit den Memberfunktionen bezog sich auf die Aussage von zynikus und die wiederrum bezog sich auf meine Aussage, die Kontextabhängig war. Also doch ein indirekter Bezug zum Medienverleih. 😉

    volkard schrieb:

    Nathan schrieb:

    Mein Gott seid ihr kleinlich!
    Der TE will Polymorphie, also muss er virtual verwenden. Punkt.

    Polymorphismus könnte man auch ganz anderes erreichen.

    Js? Wie denn?



  • Nathan schrieb:

    Wie denn?

    Mit switch zum Beispiel.



  • Ich will nun ungern einen neuen Thread aufmachen, aber darf ich hier nochmal bei einer einfachen Sache um Hilfe bitten?

    #include <iostream>
    #include <iomanip>
    #include <cstdio>
    using namespace std;
    
    int main()
    {
        int Hauptmenu_Eingabe;
        int AlleMedienMenu_Eingabe;
    
        while (Hauptmenu_Eingabe != 0){
            cout << "Hauptmenu_Eingabe: ";
            cin >> Hauptmenu_Eingabe;
    
            switch (Hauptmenu_Eingabe) {
                case 1:
                    while (AlleMedienMenu_Eingabe != 0){
                        cout << "AlleMedienMenu_Eingabe: ";
                        cin >> AlleMedienMenu_Eingabe;
    
                        switch (AlleMedienMenu_Eingabe) {
                            case 1:
                                break;
                        }
                    }
                break;
            }
        }
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

    Ich habe echt keinen blassen schimmer mehr, wieso der wenn ich im Hauptmenü 1 wähle, im Alle Medien Menü dann sage 0 er danach nie wieder in das Alle Medien menü geht.

    Ich drücke Quasi: 1
    0
    1
    (und hier sollte er wieder in das Alle Medien Menü gehen, tut er nur leider nicht :/)



  • AlleMedienMenu_Eingabe ist eben immer noch 0. Du solltest deine Variablen ordentlich initialisieren, bevor du sie für Schleifenbedingungen verwendest.



  • Initialisiere die Variablen mit einem Wert ungleich 0.



  • Auch mit Initialisierung habe ich dieses Problem. Auch Ohne breaks habe ich das Problem ... und ob ich Case 0 weg lasse oder nicht, ändert auch nichts.



  • Yaerox schrieb:

    Auch mit Initialisierung habe ich dieses Problem.

    Dann hast du's falsch gemacht. Zeig den Code.



  • #include <iostream>
    #include <iomanip>
    #include <cstdio>
    using namespace std;
    
    int main()
    {
        int Hauptmenu_Eingabe = 1;
        int AlleMedienMenu_Eingabe = 1;
    
        while (Hauptmenu_Eingabe != 0){
            cout << "Hauptmenu_Eingabe: ";
            cin >> Hauptmenu_Eingabe;
    
            switch (Hauptmenu_Eingabe) {
                case 1:
                    while (AlleMedienMenu_Eingabe != 0){
                        cout << "AlleMedienMenu_Eingabe: ";
                        cin >> AlleMedienMenu_Eingabe;
    
                        switch (AlleMedienMenu_Eingabe) {
                            case 1:
                                break;
                            case 0:
                                break;
                        }
                    }
                    break;
                case 0:
                    break;
            }
        }
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    

Log in to reply