header / cpp
-
FreakyBKA schrieb:
naja die #ifndef sachen hab ich ja drin falls ich indirekt zweimal den gleichen header einbinde und der dann nicht rummeckert, das er den schon kennt.
Die Includeguards gehören ausschließlich in die Dateien die du inkludierst (Sprich Header). Davon abgesehen ist es üblich Makros (defines) immer groß zu schreiben. Semikolons sind an den von Nexus erwähnten stellen unnötig (und gehören dort auch nicht hin), der Compiler wird dies aber durchgehen lassen.
Also ganz kurz das Beispiel angepasst:
// foo.h
#ifndef FOO_HEADER #define FOO_HEADER class foo { public: foo(); }; #endif// foo.cpp
#include "foo.h" foo::foo() { }// main.cpp
#include "foo.h" int main() { foo f; }cu André
-
dann versteh ich aber nicht woher eine andere datei, in der ich nur die header inkludieren würde, weiß wie die entsprechenden definitionen aussehen. ich mein der sieht doch in seinem code dann nur die deklarationen ohne die definitionen.
also wenn ich mir irgendwo fooA.h und fooA.cpp definiere und nur fooA.cpp die fooA.h includiert. wenn ich jetzt in fooB.h die fooA.h includieren dann kennt die doch die ganzen definitionen aus fooA.cpp nicht, oder bin ich da jetzt auf dem flaschen dampfer? oder wenn ich in der main.cpp einfach nur fooA.h includiere, ist das ja der ähnliche fall.
-
Makro (defines) schreib ich sonst auch immer groß, hab hier jetzt nur der schnelle halber nicht darauf geachtet.
-
FreakyBKA schrieb:
also wenn ich mir irgendwo fooA.h und fooA.cpp definiere und nur fooA.cpp die fooA.h includiert.
Wie oft müssen wir dir noch sagen, dass man keine CPP-Dateien in Header inkludiert?
Es macht bei einer Klasse nichts, wenn die Definition von deren Memberfunktionen nicht bekannt ist, solange du die Funktionen nicht aufrufst.
-
hab ich doch auch gar nicht geschrieben, dass ich .cpp in .h inkludiere sondern umgedreht.
main.cpp
#include "fooA.h" /*deklariert die klasse fooA*/ int main() { fooA A; return 0; }hier versteh ich dann nicht woher die main.cpp weiß wie die fooA-Klasse definiert ist?
-
FreakyBKA schrieb:
main.cpp
#include "fooA.h" /*deklariert die klasse fooA*/ int main() { fooA A; return 0; }hier versteh ich dann nicht woher die main.cpp weiß wie die fooA-Klasse definiert ist?
Ganz einfach: gar nicht!
Der Compiler benötigt nur eine Deklaration. Die ist in der Headerdatei vorhanden. Der Compiler merkt nun, dass die Definition nicht in der gleichen Quelldatei ist und markiert das in der erzeugten Objektdatei entsprechend.
Im zweiten Schritt kommt der Linker (dieser benötigt die Definitionen) und ersetzt diese Markierungen durch Verweise auf den aus einer anderen Quelldatei erstellten Funktionen.
-
*schnipp*
Da hatte es 2 Seiten..

-
Ups sorry, da hab ich nicht genau gelesen

Um mal die beiden vorherigen Beiträge zu ignorieren (:p):
Wie gesagt, so lange du keine der noch nicht definierten Funktionen aufrufst, geht alles ohne Probleme. Wenn du aber einen neuen Standardkonstruktor schreibst, muss dieser definiert sein, damit du eine Instanz der Klasse erstellen kannst.
Beim Aufruf nicht-definierter Funktionen erhältst du diesen Linker-Error: error LNK2001: Nicht aufgelöstes externes Symbol ""public: __thiscall ...
-
Beim Aufruf nicht-definierter Funktionen erhältst du diesen Linker-Error: error LNK2001: Nicht aufgelöstes externes Symbol ""public: __thiscall ...
genau das erhalte ich jetzt, nachdem ich überall die inkludierung der cpp-dateien aus den header-dateien rausgenommen habe

Im zweiten Schritt kommt der Linker (dieser benötigt die Definitionen) und ersetzt diese Markierungen durch Verweise auf den aus einer anderen Quelldatei erstellten Funktionen.
woher nimmt er die verweise? er weiß doch gar nicht wo ich die entsprechende .cpp habe.
-
Doch. Dafür werden ja die anderen Source Dateien mitgelinkt.
-
dh ich muss jede einzelne cpp-Datei, die ich irgendwann mal erstellt habe und verwenden will, mit ins projekt aufnehmen? genau das wollte ich eigentlich vermeiden um das projekt übersichtlich zu halten.
-
FreakyBKA schrieb:
Beim Aufruf nicht-definierter Funktionen erhältst du diesen Linker-Error: error LNK2001: Nicht aufgelöstes externes Symbol ""public: __thiscall ...
genau das erhalte ich jetzt, nachdem ich überall die inkludierung der cpp-dateien aus den header-dateien rausgenommen habe

Zeig doch mal deinen aktuellen Code. Das sollte eigentlich nicht passieren. Du hast ja die benötigten Methoden schon definiert, oder?
-
ja ich hab die methoden definiert, allerdings hab ich halt nich die cpp-datei mit im projekt drin. das wollte ich halt der übersicht wegen nicht.
-
FreakyBKA schrieb:
dh ich muss jede einzelne cpp-Datei, die ich irgendwann mal erstellt habe und verwenden will, mit ins projekt aufnehmen? genau das wollte ich eigentlich vermeiden um das projekt übersichtlich zu halten.
Du könntest natürlich auch eine Dll aus den Teilen machen, die du sicher brauchst und sicher nicht mehr geänder werden. Dann musst du da nur noch die Header includen , die libs linken und dll in den Ordner kopieren.
-
es halt so das ich mir viele klassen selbst definiert hab und die möchte ich einfach inkludieren können ohne das ich jedesmal extra die cpp-datei mit ins projekt aufnehmen muss, und dachte ich halt ich schreib das einfach in die header-datei mit rein. das hat ja auch prima funktioniert, bis ich jetzt mit Qt arbeite und da noch ein paar andere sachen mit diversen header-files gemacht werden müssen und dann meckert er da rum, das halt alles schon mal irgendwo definiert wurde.
-
wie funktioniert das denn mit den dll/lib erstellen und linken?
-
-
es halt so das ich mir viele klassen selbst definiert hab und die möchte ich einfach inkludieren könnenakzeptiers: inkludieren geht einfach nicht.
Das muss immer dazu gelinkt werden. Du musst deswegen aber nicht alle im Projekt haben. Du kannst sie entweder zu einer lib oder dll zusammenfassen, oder, was in einer IDE imho allerdings merkwürdig wäre, die .o files in den Linkeroptionen direkt dazu linken.Aber ein Tipp: Wenn du gebrauch von einer ordentlichen Ordnerstruktur machst, anstatt alles einfach hin zu klatschen, hättest du auch kein Problem mehr mit den ganzen Dateien.
(Wenn es sich allerdings um Dinge handelt, die du in mehreren Projekten verwenden willst, oder die zusammen eine logische Einheit bilden, ist eine Bibliothek schon sehr sinnvoll)ach und noch etwas:
.cpp Dateien inkludierst du nichtmfg
-.-PS:
nein, du inkludierst sie nicht
-
ach und noch etwas:
.cpp Dateien inkludierst du nichtSehr selten doch.. z.B Templates.
-
Chewie83 schrieb:
FreakyBKA schrieb:
main.cpp
#include "fooA.h" /*deklariert die klasse fooA*/ int main() { fooA A; return 0; }hier versteh ich dann nicht woher die main.cpp weiß wie die fooA-Klasse definiert ist?
Ganz einfach: gar nicht!
Der Compiler benötigt nur eine Deklaration. Die ist in der Headerdatei vorhanden. Der Compiler merkt nun, dass die Definition nicht in der gleichen Quelldatei ist und markiert das in der erzeugten Objektdatei entsprechend.
das stimmt nicht. um ein objekt zu erstellen, muss der compiler wissen, wie es aufgebaut ist, dh. er braucht seine definition.
der unterschied zwischen deklaration und definition:
class Foo; class Foo { };ersteres ist die deklaration, zweiteres die definition der klasse foo. verwirrenderweise hat es sich eingebürgert, die deklaration einer klasse "vorwärtsdeklaration" zu nennen.
@OP: es gibt hier öfter mal threads, die sich mit demselben problem beschäftigen, das du hast. stichworte, nach denen du dich erkundigen musst sind: übersetzungseinheit, linker und die one-definition-rule (ODR). letztere besagt zwar, dass es in einem programm nur eine definition für jede entität geben darf, hat jedoch viele ausnahmen (z.b. klassen, templates, inline-funktionen)
ein weiteres verständnisproblem, das du zu haben scheinst, ist, dass du denkst, der compiler könne nicht wissen, wie eine klasse aufgebaut ist, wenn er nur deren "deklaration" (und du meinst: definition) hat. aber genau hier ist die klasse beschrieben: dieses und jenes objekt ist member, und außerdem stellt die klasse verschiedene funktionen zur verfügung.
struct Foo { int a, b; void foo (); };Foo ist definiert. Foo besteht aus zwei sub-objekten (hier ints), damit weiß der compiler, wie groß ein objekt vom typ Foo sein muss und kann - wenn du ein objekt erstellst (definierst) entsprechenden speicher reservieren.
dass die funktion foo hier nicht definiert ist, sondern nur deklariert, stört nicht, denn funktionen sind keine objekte und tragen daher auch nicht zur größe des objektes bei. d.h. die definition von foo kann auch in einer anderen übersetzungseinheit stehen, der linker sorgt dann dafür, dass die richtige funktion aufgerufen wird. ein sonderfall sind natürlich inline-funktionen, wo der linker sicherstellen muss, dass es - obwohl die funktion "mehrfach" definiert ist - nur eine (tatsächlich) repräsentation der funktion im speicher gibt. aber das ist ein anderes kapitel.