Anfänger - Linkerfehler: undefined reference



  • Hallo

    Ich bin gerde dabei, ein bisschen mit Klassen, Vererbung und Konstruktoren rumzuspielen, da ich am Mittwoch Prüfung schreibe. Ich benute Dev C++ als Entwicklungsumgebung.

    Zu meinem Problem, ich habe einen eigentlich relativ einfachen code geschrieben.

    Er besteht aus der Klasse Tier und der Klasse Hund, die von Tier erbt.
    Tier hat zwei Konstruktoren, Hund einen, der in der Initialiserungsliste einen der Tier-Konstuktoren aufruft. Außerdem hat Hund noch einen Kopierkonstruktor.

    Ziel war es , einfach mal die ganze Sachen nochmal durchzuspielen und dabei die Fragen, auf die ich stoße abzuarbeiten. Leider bekomme ich bei meinem Code aber einen linker-Fehler und weiß nicht warum. Ich suche schon seit ner halben Stunde, aber ich finde den Fehler nicht, vielleicht kann mir jemand helfen?

    Hier mal der Code der Klassendefinition und Deklaration

    #include <string>
    #include <iostream>
    
    using namespace std;
    
    class Tier {
          protected:
                  string name;
                  int beine;
                  int hoehe;
          private:
                  Tier();     //standardkonstrukor private
          public:
                 //Konstruktoren
    //             Tier(int _beine, int _hoehe);
                 Tier(string _name, int _beine, int _hoehe);
    
                 //Destruktor
                 virtual ~Tier();
    
                 // Zugriffsmethoden
                 const string& getName() const;  // Const, wg lesezugriff über const referenz
                 int getBeine() const;
                 int getHoehe() const; 
    
                 void setName(string _name);            
                 void setBeine(int _beine);
                 void setName(int _hoehe);
    
                 void gibLaut();   // später auf virtual setzen
    
                 };
    
    class Hund : public Tier {
          private:
                  string rasse;
    
          public:
                 //Konstruktoren
                 Hund(string _name, int _hoehe, string _rasse);  // MERKEN: LISTE NICHT HIER
    
                 //Kopierkonstruktor
                 Hund(const Hund& _andererHund);
    
                 // Destruktor
                 ~Hund();
    
                 //Zugriffsmethoden 
                 const string& getRasse() const;       
                 void setRasse(string& _rasse);  
    
                 void gibLaut();  // wird überschrieben  
          };
    
    // Definition der Klassen
    
    // ***************** Tier ******************
    
    Tier::Tier(int _beine, int _hoehe):
                       beine(_beine),hoehe(_hoehe)
                       {}
    
    Tier::Tier(string _name, int _beine, int _hoehe):
                       name(_name),beine(_beine),hoehe(_hoehe)
                       {}
    
    Tier::~Tier() {          
            cout <<   "Ich bin der Destruktor der Basisklasse";      
            }
    
    int Tier::getBeine() const {return (beine);}
    int Tier::getHoehe() const {return (hoehe);}
    const string& Tier::getName() const {return (name);} 
    
    void Tier::gibLaut() {
         cout << "Ich kann keine Laute von mir geben, ich weiß nicht was für ein Tier ich bin";
         }
    
         // ******************HUNDE************************
    
    Hund::Hund(string _name, int _hoehe, string _rasse) : Tier::Tier(_name,4,_hoehe),rasse(_rasse) {}
    
    const string& Hund::getRasse() const {
          return rasse;
          }
    
    // Kopierkonstruktor 
    Hund::Hund(const Hund& _andererHund):Tier::Tier(_andererHund.beine,_andererHund.hoehe){
                     name = _andererHund.getName();
                     rasse = _andererHund.getRasse();
                     // macht das der string - kopierkonstruktor? Prüfen!
                     }
    
    Hund::~Hund() {
                  cout << "Ich bin der Hunde-Destruktor";
    }
    void Hund::gibLaut() {
         cout << "Wau Wau";
         }
    

    Der Linker sagt:
    [Linker error] undefined reference to 'Tier::Tier(int,int)'
    [Linker error] undefined reference to 'Hund::getRasse() const'
    [Linker error] undefined reference to 'Tier::Tier(int,int)'
    [Linker error] undefined reference to 'Hund::getRasse() const'
    Id returned 1 exit status



  • ChaosNo1 schrieb:

    Hund::Hund(string _name, int _hoehe, string _rasse) : Tier::Tier(_name,4,_hoehe),rasse(_rasse) {}
    

    Basisklassenkonstruktoren ruft man in der Initialisierungsliste auf, indem man den Bezeichner nur einmal setzt:

    Hund::Hund(const string& _name, int _hoehe, const string& _rasse) // Const-Referenz!
    : Tier(_name, 4, _hoehe)  // Tier statt Tier::Tier
    , rasse(_rasse)
    {
    
    }
    

    Gleiches gilt für den anderen Konstruktor. Allerdings sollte das zu einem Compiler- und nicht Linkerfehler führen. Sieht denn dein Code genau so aus, wie du ihn aufgeschrieben hast?

    Weshalb machst du den Standardkonstruktor von Tier eigentlich privat? Sobald du selber Konstruktoren deklarierst, wird der Standardkonstruktor nicht mehr automatisch generiert.



  • Hallo,

    danke erstmal für die Antwort!

    ja, der code ist 1:1

    Leider bekomme ich noch immer den selben Linker-Fehler 😕

    Ich mache den Standard-Konstruktor privat, weil ich erwzingen will, einen Konstruktor zu benutzen, der Parameter annimmt. Zumindest so die Theorie - weil ich dachte gelesen zu haben, dass der Compiler den Standarkonstruktor immer automatisch generiert.



  • Was ist denn das für ein strubbeliger Compiler, der diesen Code schluckt, aber dann Linkerfehler ausspuckt?



  • //Konstruktoren
    //             Tier(int _beine, int _hoehe);
                 Tier(string _name, int _beine, int _hoehe);
    

    Auskommentieren, aber dann implementieren... 😉



  • Hi,

    danke, ich glaub das wars 😉

    kann ich noch ne andere Frage stellen (wenn ich neues Thema aufmachen soll, bitte sagen 😉 )

    Es geht um die strings und den Kopierkonstruktor.

    Muss ich diese im Kopierkonstruktor kopieren oder kann ich die einfach in der initialisierungsliste zuweisen?

    Die strings sind ja als "normale" objekte angelegt und daher für micht nicht dynamisch ( wenn man mal davon absieht, was dahinter passiert). und normale Objekte werden doch einfach kopiert, so dass es eigentlich zu dem Problem mit der flachen Kopie gar nicht kommen kann, oder?



  • ChaosNo1 schrieb:

    Die strings sind ja als "normale" objekte angelegt und daher für micht nicht dynamisch ( wenn man mal davon absieht, was dahinter passiert). und normale Objekte werden doch einfach kopiert, so dass es eigentlich zu dem Problem mit der flachen Kopie gar nicht kommen kann, oder?

    so isses.

    du brauchst keinen destruktor, wie ich sehe. dann brauchste normalerweise auch keinen kopierkonstruktor und keinen zuweisungsoperator.



  • Danke 😉

    ja, das mit den destruktor ist auch mehr zum testen 😉



  • ChaosNo1 schrieb:

    Ich mache den Standard-Konstruktor privat, weil ich erwzingen will, einen Konstruktor zu benutzen, der Parameter annimmt. Zumindest so die Theorie - weil ich dachte gelesen zu haben, dass der Compiler den Standarkonstruktor immer automatisch generiert.

    Das ist wie gesagt falsch. Der Standardkonstruktor wird nur automatisch generiert, wenn keine benutzerdefinierten Konstruktoren vorhanden sind.

    ChaosNo1 schrieb:

    danke, ich glaub das wars 😉

    Wenn es das wirklich war, solltest du unbedingt den Compiler wechseln. Wenn nicht deklarierte Bezeichner erst auf Linker-Ebene zu einem Fehler führen und Basisklassenkonstruktoren mit Tier::Tier aufgerufen werden können, bringt der Compiler nicht viel. Was für einen benutzt du überhaupt?



  • Nexus schrieb:

    ChaosNo1 schrieb:

    danke, ich glaub das wars 😉

    Wenn es das wirklich war, solltest du unbedingt den Compiler wechseln. Wenn nicht deklarierte Bezeichner erst auf Linker-Ebene zu einem Fehler führen und Basisklassenkonstruktoren mit Tier::Tier aufgerufen werden können, bringt der Compiler nicht viel. Was für einen benutzt du überhaupt?

    ChaosNo1 schrieb:

    Ich benute Dev C++ als Entwicklungsumgebung

    Nimm Code::Blocks (ist der Nachfolger von DevC++) - oder noch besser, nimm MSVC:
    http://www.microsoft.com/express/vc/

    bb



  • Habe zwischenzeitlich das ganze auf Vstudio implementiert und es nochmal ausprobiert. Dort hat der Compiler auch den Fehler angezeigt und nicht der Linker.

    Und ich dachte immer Dev-C++ soll so gut sein. Wusste gar nicht, dass es da einen Nachfolger gibt 😉

    @Nexus: danke für den Hinweis, du hast recht. Aber in den Unterlagen von meinem Prof steht, dass es nicht sehr elegant ist, weil der Compiler einen Fehler ausspuckt, wenn der Standardkonstruktor fehlt. Um diesen Fehler zu umgehen, schlägt er vor, den Standarkonstruktor als private zu deklarieren.

    Danke für die Hilfe!



  • ChaosNo1 schrieb:

    Und ich dachte immer Dev-C++ soll so gut sein.

    Naja - früher war es das vll mal - aber es gilt schon ziemlich lange als deprecated - d.h. du solltest es nicht mehr nutzen...

    ChaosNo1 schrieb:

    Aber in den Unterlagen von meinem Prof steht, dass es nicht sehr elegant ist, weil der Compiler einen Fehler ausspuckt, wenn der Standardkonstruktor fehlt. Um diesen Fehler zu umgehen, schlägt er vor, den Standarkonstruktor als private zu deklarieren.

    Ich kenn DevC++ zwar nicht aus eigener Erfahrung, aber ich kann mir solch ein Verhalten auch nicht beim schlechtesten Compiler der Welt vorstellen...
    Zitier mal das, was dein Prof. da geschrieben hat - ich wette, er hat was anderes geschrieben oder zumindest sagen wollen ^^

    bb



  • ChaosNo1 schrieb:

    @Nexus: danke für den Hinweis, du hast recht. Aber in den Unterlagen von meinem Prof steht, dass es nicht sehr elegant ist, weil der Compiler einen Fehler ausspuckt, wenn der Standardkonstruktor fehlt. Um diesen Fehler zu umgehen, schlägt er vor, den Standarkonstruktor als private zu deklarieren.

    Wenn er das wirklich vorschlägt, hat er wohl nicht gerade viel Ahnung. Naja, lass den Standardkonstruktor einfach weg, ein brauchbarer Compiler macht keine Probleme deswegen. Unter Windows kann ich dir auch nur MSVC++ empfehlen, diese IDE ist wirklich sehr gut.



  • Und achte bitte ein wenig auf deine Einrückung. Dann sieht das ganze auch gleich viel besser aus. Immerhin benutzt du schon const. 👍
    Dann solltest du lediglich die Unterstriche von dem Bezeichner Anfang wegnehmen. (sind für Compiler reserviert)



  • drakon schrieb:

    Dann solltest du lediglich die Unterstriche von dem Bezeichner Anfang wegnehmen. (sind für Compiler reserviert)

    imho gilt das nur für 2 unterstriche oder 1unterstrich + großbuchstabe am anfang!?

    bb


Anmelden zum Antworten