Nicht definierter Verweis



  • Hi,
    ich sitze schon relativ lange an diesem Problem, und sehe einfach nicht wie ich es lösen kann. Vielleicht könnt ihr mir ja helfen..

    Ich habe zwei Klassen. Student ist eine Unterklasse von Mensch und meine superclasses ist die "main Methode".

    //superclasses.cpp
    #include <iostream>
    #include <string.h>
    #include <string.h>
    #include "Mensch.h"
    #include "Student.h"
    using namespace std;
    
    int main(int argc, char** argv)
    {
    	int Alter;
    	char Beruf[20];
    	char Name[20];
    
    	Student* Lukas = new Student();
    
    	cout << "Name ?" << endl;
    	cin >> Name	;
    	Lukas->Mensch::setName(Name);
    	cout << "Wie alt ?" << endl;
    	cin >> Alter;
    	Lukas->Mensch::setAlter(Alter);
    	cout << "Welcher Beruf ?" << endl;
    	cin >> Beruf;
    	Lukas->Mensch::setBeruf(Beruf);
    
    	cout << Lukas->Name << " ist " << Lukas->Alter << " Jahre alt und ist von Beruf " << Lukas->Beruf << endl;
    	cout << Lukas->Student::Uni << endl;
    
    	delete Lukas;
    
    }
    
    //Mensch.cpp
    #include <iostream>
    #include <string.h>
    #include <string.h>
    #include "Mensch.h"
    using namespace std;
    
    Mensch::Mensch()
    {
    	strcpy(this->Name,"noname");
    	this->Alter=0;
    	strcpy(this->Beruf,"nojob");
    }
    
    Mensch::~Mensch()
    {
    }
    
    void Mensch::setAlter(int Alter)
    {
    	this->Alter=Alter;
    }
    
    void Mensch::setBeruf(char Beruf[20])
    {
    	strcpy(this->Beruf,Beruf);
    }
    
    void Mensch::setName(char Name[20])
    {
    	strcpy(this->Name,Name);
    }
    
    //Mensch.h
    class Mensch
    {
    public:
    	char Name[20];
    	int Alter;
    	char Beruf[20];
    
    	Mensch();
    	~Mensch();
    	void setAlter(int Alter);
    	void setBeruf(char Beruf[20]);
    	void setName(char Name[20]);
    };
    
    //Student.cpp
    #include <iostream>
    #include <string.h>
    #include <string.h>
    #include "Student.h"
    #include "Mensch.h"
    using namespace std;
    
    Student::Student()
    {
    	strcpy(this->Uni,"none");
    }
    
    Student::void setUni(char Uni[20])
    {
    	strcpy(this->Uni,Uni);
    }
    
    //Student.h
    class Student : public Mensch
    {
    public:
    	char Uni[20];
    
    	Student();
    	void setUni(char Uni[20]);
    };
    

    Ich bekomme immer diese oder eine ähnliche Fehlermeldung:

    1 error generated.
    Lukass-MacBook-Pro:Oberklassenbeispiel Lukas$ g++ superclasses.cpp
    Undefined symbols for architecture x86_64:
      "Mensch::setName(char*)", referenced from:
          _main in superclasses-0902b0.o
      "Mensch::setAlter(int)", referenced from:
          _main in superclasses-0902b0.o
      "Mensch::setBeruf(char*)", referenced from:
          _main in superclasses-0902b0.o
      "Mensch::~Mensch()", referenced from:
          Student::~Student() in superclasses-0902b0.o
      "Student::Student()", referenced from:
          _main in superclasses-0902b0.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    


  • Du musst ja auch irgendwo die anderen *.cpp Dateien compilieren und dazu linken. Die einfache Lösung für ein paar wenige Dateien ist einfach alle *.cpp Dateien beim g++ Aufruf anzugeben:

    g++ superclasses.cpp Mensch.cpp Student.cpp
    

    Allerdings werden dann immer alle *.cpp Dateien neu compiliert. Besser geht es durch die Verwendung von Makefiles oder einer Entwicklungsumgebung.



  • Bitte nimm als erstes std::string anstelle von den char[]Arrays!

    Dann zu deinem eigentlichen Problem: Du musst mensch.cpp natürlich auch kompilieren, das passiert nicht automatisch (wenn man g++ über die Konsole verwendet, bei einer vernünftigen IDE ist das kein Problem)



  • Mist, das hab ich voll vergessen..

    Vielen Dank, ihr habt mir sehr geholfen 🙂



  • LukasUebt schrieb:

    Ich habe zwei Klassen. Student ist eine Unterklasse von Mensch und meine superclasses ist die "main Methode".

    Naja. Nicht wirklich. main() ist eine Funktion und keine Methode und superclasses sehe ich hier nicht. Hast Du mal Java programmiert?



  • LukasUebt schrieb:

    char Name[20];
      
      [...]
    
      cin >> Name	;
    

    ganz schön mutiger Stunt, den Du da übst 🙂

    scnr



  • klassenmethode schrieb:

    LukasUebt schrieb:

    char Name[20];
      
      [...]
    
      cin >> Name	;
    

    ganz schön mutiger Stunt, den Du da übst 🙂

    scnr

    wenn ein Anfänger so einen Fehler macht wäre es natürlich hilfreich zu sagen, was da nicht passt.

    @Threadstarter: der gezeigte Code macht folgendes: es reserviert 20 Zeichen im Speicher. Einlesen tust du dann aber bis der User mit der Eingabe fertig ist.
    D.h. cin weiß nicht wann der zugewiesene Speicher vorbei ist. Danach wird einfach der dahinterliegende Speicher überschrieben. Je nachdem was überschrieben wird passiert entweder garnicht, oder es knallt, oder es treten komische Effekte zu Tage.

    Probiers einfach mal aus und gib einen Text der Länge 40 ein ... wenn das kein Problem ist dann probiers mit 80 Zeichen ... irgendwann solltest du einen Effekt feststellen.

    P.S.: nimm einfach std::string statt char[] und das Problem ist gelöst.



  • Was mir gleich auffällt ist die Verwendung vom Heap statt Stack. Sicherer und einfacher wäre das so:

    #include <iostream>  // nicht alles mögliche includen sondern nur was notwendig ist
    #include "Student.h"
    
    using namespace std;   // würde ich nicht verwenden, aber das ist Geschmackssache; lieber im code std::cout usw.
    
    int main(int argc, char** argv)
    {
    ...
    	Student Lukas;  // legt eine Instanz auf den Stack
    	cout << "Name ?" << endl;
    	cin >> Name;
    	Lukas.setName(Name);  // so ist es doch ganz einfach
    ...
    	//delete Lukas;  // Löschen geschieht hier jetzt automatisch
    
    }
    


  • Da hab ich mal ne Frage, was für einen Unterscheid macht es, Objekte auf dem Stack oder dem Heap zu erzeugen?

    Im Kontext von Late-binding und Inheritance sehe ich das ein, da kann ich ner Base Class Referenz später variabel Objekte zuordnen, aber hier?



  • Sewing schrieb:

    Da hab ich mal ne Frage, was für einen Unterscheid macht es, Objekte auf dem Stack oder dem Heap zu erzeugen?

    Erkläre mir mal die Unterschiede zwischen Stack und Heap. Dabei geht es ja nicht nur um was man machen kann mit den Objekten die dort liegen, sondern diese beiden Speicherbereiche haben ja auch unterschiedliche Eigenschaften - was zB Geschwindigkeit, Größe, etc. betrifft.



  • Kann ich leider nicht, wäre aber froh, wenn du das tust?

    Klar müsste er danach explizit delete aufrufen

    was sind weitere Unterschiede an dieser Stelle?



  • Sewing schrieb:

    Da hab ich mal ne Frage, was für einen Unterscheid macht es, Objekte auf dem Stack oder dem Heap zu erzeugen?

    Im Kontext von Late-binding und Inheritance sehe ich das ein, da kann ich ner Base Class Referenz später variabel Objekte zuordnen, aber hier?

    Von der Logik her ist es erst mal so, dass man ein delete mal vergessen kann. Liegt das Objekt auf dem Stack, kann das gar nicht passieren.

    Das vorliegende Beispiel ist natürlich zu einfach, aber man denke nur man an exception safety. Wirft eine der Methoden eine Exception, dann wird das delete übersprungen und es entsteht ein Memory leak.

    Smartpointer sind eine Lösung, die helfen würden. Aber sie sind erst die zweit beste Lösung.

    In diesem Fall gibt es keinen Grund, das Objekt dynamisch auf dem Heap anzulegen. Daher sollte man es auf dem Stack machen.

    Technisch gibt es weitere Entscheidungshilfen. Der Stack ist in der Regel kleiner als der Heap, dafür schneller.


Log in to reply