header / cpp
-
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.
-
ich habe sehr wohl eine gute ordnerstruktur und packe nicht alle meine cpp und h dateien in einen ordner, sondern jede klasse in einen eigenen ordner um es übersichtlich zu halten. also das problem ist dann wohl das fast alle meine klasse template-klassen sind, da ich diese klassen so allgemein wie möglich halten wollte um sie auf viele probleme anwenden zu können.
hab ich das dann jetzt richtig verstanden das wenn ich eine klasse als template deklariere muss ich die cpp mit im header einbinden?
zudem hab ich viele (wenn nicht sogar fast alle) meiner klassen-funktionen als inline definiert, mir hat mal wer gesagt, dass das den code evtl schneller macht, man aber trotzdem die logische trennung von deklaration und definition hat.
-
FreakyBKA schrieb:
ich habe sehr wohl eine gute ordnerstruktur und packe nicht alle meine cpp und h dateien in einen ordner, sondern jede klasse in einen eigenen ordner um es übersichtlich zu halten.
Das wird bei großen Projekten sogar sehr unübersichtlich (Ewig verschachtelte Ordnerstruktur; Mein Kompromiss ist die Unterteilung nach Namensräumen)...
FreakyBKA schrieb:
hab ich das dann jetzt richtig verstanden das wenn ich eine klasse als template deklariere muss ich die cpp mit im header einbinden?
Templates werden üblicherweise ausschließlich in den Header geschrieben (die andere Variante ist die Trennung mit einem von cpp unterscheidbaren Namenskürzel z.B. tmpl) da Templates immer ganz benötigt werden.
Beispiel bei Trennung eines Templates:
foo.h
#if !defined(FOO_HEADER) #define FOO_HEADER template<typename T> class foo { public: foo(); }; #endiffoo.tmpl
#include "foo.h" template<typename T> foo<T>::foo() {}main.cpp
#include "foo.tmpl" int main() { foo<int> f; }FreakyBKA schrieb:
zudem hab ich viele (wenn nicht sogar fast alle) meiner klassen-funktionen als inline definiert, mir hat mal wer gesagt, dass das den code evtl schneller macht, man aber trotzdem die logische trennung von deklaration und definition hat.
Zum einen macht dies nur Sinn wenn die Methoden klein sind, zum anderen ist dies für den Compiler auch nur eine "Anregung", ob der Methoden inline umsetzt ist seine Sache (Wenn ja, erhöht dies aber im Gegenzug die Größe des Programmes; Es gibt nichts umsonst ;p).
cu André
-
FreakyBKA schrieb:
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.
Etwas Off-Topic, aber mich interessiert es dennoch.
Ist die Deklaration einer Klasse wirklich schon mit dem Namen und den Basisklassen abgeschlossen oder gehört die Deklaration der Attribute und Methoden nicht auch zur Deklaration dazu? Ich würde sagen, sie gehören dazu, denn eine Klasse ohne ihre Attribute ist noch nicht hinreichend beschrieben.
Andererseits ist die Vereinbarung eines Attributes gleichzeitig Deklaration und Definition, sodass im obigen Fall eine Deklaration eine Definition enthalten würde.
Ist aus meiner Sicht also gar keine so einfache Sache, die genaue Grenze zwischen Definition und Deklaration bei Klassen zu ziehen.
Gibt es für C++ einen diesbezüglichen Kanon?
-
das beispiel war vielleicht etwas missverständlich:
class Foo { };ist schon eine definition, nämlich die einer klasse, die gar keine member hat.
leer ist sie dennoch nicht, zumindest eine gewisse größe muss sie haben (jedes objekt in C++ muss eine bestimmte, eindeutige, speicherstelle belegen). du hast auch keine möglichkeit mehr, an der definition von Foo etwas zu ändern. zugegeben, eine leere klasse ist meist ein bisschen sinnlos.zur definition einer klasse gehört die deklaration ihrer elementmethoden (und die definition ihrer elementvariablen) sowie das angeben eventueller basisklassen.
zur definition einer klasse gehört das angeben ihres namens.
die grenze muss irgendwo definiert sein, und ist es auch genau da, wo der compiler weiß, wie er ein objekt erstellen kann. kann er es nicht, ist es mit sicherheit keine definition.
class Foo; //deklaration Foo a; //fehler: definition, aber Foo ist nicht definiert Foo* b; //ok, zeiger auf eine klasse (in dem fall foo) ist definiert Bar* c; //fehler: Bar ist nicht deklariert, zeiger auf (irgendetwas) gibt es nicht class Foo {}; Foo d; //ok: Foo ist definiert struct Bar { void foo(); }; Bar e; //OK, Bar ist definiert e.foo(); //OK, foo ist eine elementmethode von Bar void Bar::foo () {} //wird aber erst hier definiert. //ansonsten gäbe es einen fehler wie "undefined refence", aber vom linker!
-
Was imho Verständnis Probleme geben kann ist, dass die Definition der Elementfunktionen als "Definition der KLasse" bezeichnet wird.