Forum: PC-Programmierung Eclipse, C++: undefined reference


von Eichhörnchen (Gast)


Lesenswert?

Guten Mittag,

ich habe das Problem in Eclipse, dass von meinem C++ Klassen nur jene 
verwendet werden können, welche nicht in Header und Source Dateien 
getrennt sind.

Genauer gesagt, wenn ich per #include einen Klassen-Header einfüge kann 
ich nur jene Methoden verwenden, welche direkt im Header auch 
definiert+deklariert sind.

Jene Methoden, welche in einer Sourcedatei deklariert werden, werfen den 
undefined-reference Fehler.

In den Projekteinstellungen ist als Source-Verzechnis das entsprechende 
Verzeichnis bereits eingestellt.

Kann mir jemand helfen? Danke!

von Dr. Sommer (Gast)


Lesenswert?

Zeige mal den Quellcode, insbesondere die Source-Dateien, und mach einen 
Screenshot vom Projektaufbau (Project explorer) in eclipse, und zeig die 
komplette(!) Ausgabe des Compilers.

von Mark B. (markbrandis)


Lesenswert?

In die Header-Datei gehört die Deklaration einer Klasse: Wie heißen die 
Member, wie heißen die Methoden.

In die cpp-Datei gehört die Implementierung der Klasse, also der Code 
der beim Aufruf der Methoden ausgeführt werden soll. Alle 
Sourcecode-Dateien, die eine bestimmte Klasse verwenden wollen, 
inkludieren die Header-Datei jener Klasse.

: Bearbeitet durch User
von Eichhörnchen (Gast)


Lesenswert?

Ok, fangen wir mal so an. Wenn ich in der main.cpp statt
1
#include "testklasse.hpp"
folgendes benutze;
1
#include "testklasse.cpp"
dann funktioniert der Code.

Main.cpp:
1
#include <iostream>
2
#include "testklasse.hpp"
3
4
int main(void) {
5
    testklasse t;
6
    t.ausserhalb();
7
    t.c = 0;
8
    t.innerhalb();
9
    int x = 0;
10
    x++;
11
    x++;
12
    x--;
13
14
        std::cout << "Hello World1" << std::endl; /* prints Hello World */
15
        std::cout << "Hello World2" << std::endl; /* prints Hello World */
16
        std::cout << "Hello World3" << std::endl; /* prints Hello World */
17
        std::cout << "Hello World4" << std::endl; /* prints Hello World */
18
        return 0;
19
}

testklasse.hpp:
1
#ifndef TESTKLASSE_H_
2
#define TESTKLASSE_H_
3
4
class testklasse {
5
public:
6
  //testklasse();
7
  void ausserhalb();
8
  char c;
9
  void innerhalb(){
10
    c = 1;
11
  };
12
};
13
14
#endif /* TESTKLASSE_H_ */

testklasse.cpp:
1
#include "testklasse.hpp"
2
3
void testklasse::ausserhalb(){
4
  c = 1;
5
}

von Dr. Sommer (Gast)


Lesenswert?

Eichhörnchen schrieb:
> folgendes benutze;#include "testklasse.cpp"
> dann funktioniert der Code.
Das ist aber furchtbar falsch. Sobald dein Projekt wächst geht das 
schief.

Eichhörnchen schrieb:
> int main(void) {
Das "void" ist überflüssig.

Zeig einen Screenshot von eclipse und den kompletten Build-Log...

von Eichhörnchen (Gast)


Angehängte Dateien:

Lesenswert?

Build Log+Screenshot:
1
03:56:04 **** Incremental Build of configuration Build (GNU) for project Test ****
2
make all 
3
make  all-recursive
4
make[1]: Verzeichnis »/home/nils/workspace/Test« wird betreten
5
Making all in src
6
make[2]: Verzeichnis »/home/nils/workspace/Test/src« wird betreten
7
arm-dey-linux-gnueabi-g++  -march=armv5te -marm -mthumb-interwork --sysroot=/opt/dey/1.6.8/sysroots/armv5te-dey-linux-gnueabi -DHAVE_CONFIG_H -I. -I..   --sysroot=/opt/dey/1.6.8/sysroots/armv5te-dey-linux-gnueabi  -g -O0  --sysroot=/opt/dey/1.6.8/sysroots/armv5te-dey-linux-gnueabi -MT Test.o -MD -MP -MF .deps/Test.Tpo -c -o Test.o Test.cpp
8
mv -f .deps/Test.Tpo .deps/Test.Po
9
../arm-dey-linux-gnueabi-libtool  --tag=CXX   --mode=link arm-dey-linux-gnueabi-g++  -march=armv5te -marm -mthumb-interwork --sysroot=/opt/dey/1.6.8/sysroots/armv5te-dey-linux-gnueabi  -g -O0  --sysroot=/opt/dey/1.6.8/sysroots/armv5te-dey-linux-gnueabi  --sysroot=/opt/dey/1.6.8/sysroots/armv5te-dey-linux-gnueabi -o Test Test.o  
10
arm-dey-linux-gnueabi-libtool: link: arm-dey-linux-gnueabi-g++ -march=armv5te -marm -mthumb-interwork --sysroot=/opt/dey/1.6.8/sysroots/armv5te-dey-linux-gnueabi -g -O0 --sysroot=/opt/dey/1.6.8/sysroots/armv5te-dey-linux-gnueabi --sysroot=/opt/dey/1.6.8/sysroots/armv5te-dey-linux-gnueabi -o Test Test.o 
11
Test.o: In function `main':
12
/home/nils/workspace/Test/src/Test.cpp:16: undefined reference to `testklasse::ausserhalb()'
13
collect2: error: ld returned 1 exit status
14
make[2]: Verzeichnis »/home/nils/workspace/Test/src« wird verlassen
15
make[1]: Verzeichnis »/home/nils/workspace/Test« wird verlassen
16
make[2]: *** [Test] Fehler 1
17
make[1]: *** [all-recursive] Fehler 1
18
make: *** [all] Fehler 2
19
20
03:56:05 Build Finished (took 688ms)

von Der E. (rogie)


Lesenswert?

*Edit: War doch richtig*

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Du benutzt ein Makefile mit automake. Das Problem hat also nichts mit 
eclipse zu tun, sondern damit dass du deine testklasse.cpp nicht in die 
Makefile.am eingetragen hast. Wenn du ein normales eclipse C++ Projekt 
anlegst brauchst du so etwas nicht zu tun, dann kompiliert eclipse 
automatisch alle .cpp Dateien im Projekt.

von Eichhörnchen (Gast)


Lesenswert?

Tatsache. Kann ich dort etwas eintragen wie, oder muss ich ab jetzt jede 
Source Datei von Hand dort eintragen:
1
Test_SOURCES = *.cpp

von I <3 make (Gast)


Lesenswert?

Eichhörnchen schrieb:
> Tatsache. Kann ich dort etwas eintragen wie, oder muss ich ab jetzt jede
> Source Datei von Hand dort eintragen:
>
>
1
> Test_SOURCES = *.cpp
2
>

Ein entschiedenes "kommt darauf an".

Wenn in deinem Projekt(*) Buildvarianten sind, hast Du von dir selbst 
bestimmte Kriterien, welche Quellcodedateien bei welchem Builddurchlauf 
dazugehören.

Z.B. UnitTest Quellcode habe ich gerne gleich bei den eigentlichen 
Quelldateien, gehört aber definitiv nicht in den Buildrun der 
production deliverable Binaries baut.

(* habe das Wort "Projekt" schon ziemlich über: damit ist in jeder Ecke 
wieder was Anderes gemeint... Grrr!)

von Wilhelm M. (wimalopaan)


Lesenswert?

Dr. Sommer schrieb:
> Eichhörnchen schrieb:
>> folgendes benutze;#include "testklasse.cpp"
>> dann funktioniert der Code.
> Das ist aber furchtbar falsch. Sobald dein Projekt wächst geht das
> schief.
>
> Eichhörnchen schrieb:
>> int main(void) {
> Das "void" ist überflüssig.

Das ist zwar jetzt off-topic:

In C bedeutet main() eine Funktion mit beliebiger (!) Parameterliste, 
und main(void) eine mit leerer Parameterliste.

In C++ bedeutet main() eine Funktion mit leerer Parameterliste.

Da main() lt. Standard genau die beiden möglichen Signaturen

1) main() / main(void)
2) main(int, char**)

hat, ist also main() in C falsch. Denn es bedeutet ja eine beliebige 
Parameterliste, und bspw. ein main(double) ist nicht zugelassen bzw. 
wird nicht als Startpunkt des User-Codes interpretiert.

s.a.

http://en.cppreference.com/w/c/language/main_function
http://en.cppreference.com/w/c/language/function_declaration

Ok, das war jetzt etwas Erbsenzählerei ....

von Wilhelm M. (wimalopaan)


Lesenswert?

Eichhörnchen schrieb:
> Tatsache. Kann ich dort etwas eintragen wie, oder muss ich ab jetzt jede
> Source Datei von Hand dort eintragen:
>
>
1
> Test_SOURCES = *.cpp
2
>

Man muss halt sehen, dass alle Implementierungsdateien kompiliert und 
gebunden werden (damit man die ODR nicht verletzt). Wie das bei welcher 
IDE wie geschieht ... ?

von tictactoe (Gast)


Lesenswert?

Eichhörnchen schrieb:
> Tatsache. Kann ich dort etwas eintragen wie, oder muss ich ab jetzt jede
> Source Datei von Hand dort eintragen:
> Test_SOURCES = *.cpp

Ja, man muss jede .cpp-Datei hinschreiben.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.