header / cpp



  • 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önnen
    

    akzeptiers: 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 nicht

    mfg
    -.-

    PS:
    nein, du inkludierst sie nicht



  • ach und noch etwas:
    .cpp Dateien inkludierst du nicht

    Sehr 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();
    };
    
    #endif
    

    foo.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.



  • also wenn ich bei template-header einfach die cpp-datei (also die einzelnen definitionen) inklude, dann hab ich doch den gleichen effekt, als wenn ich mir da so ne *.tmpl datei schreibe. da würde ich lieber im dateinamensraum von c/c++ bleiben.

    bis jetzt wurde glaube ich auch noch nicht erklärt warum man nun *.cpp nicht in header einbinden darf, sondern nur gesagt: macht man halt nicht. mit den #ifndef ... #define ... #endif schachtelungen in den jeweiligen dateien sollte das doch eigentlich kein problem sein. und schon gar nicht wenn das #include einfach nur dazu führt das der quellcode dort hinplatziert wird wo er halt steht.

    ich weiß zwar in wie weit sich die beteiligten hier mit Qt auskennen, aber mein problem ist halt das ich dort über eine header-datei einen MetaObjectCompiler(moc) laufen lassen muss. und da bekomme ich dann die fehlermeldungen das irgendwas schon definiert ist, zB:

    main.obj : error LNK2005: "public: __thiscall frm_main::frm_main(class QWidget *,class QFlags<enum Qt::WindowType>)"
     (??0frm_main@@QAE@PAVQWidget@@V?$QFlags@W4WindowType@Qt@@@@@Z) already defined in frm_main.obj
    

    was meiner meinung nach ja eigentlich nicht sein kann, da das über die #ifndef ... #endif sache ausgeschlossen sein sollte



  • die one-definition-rule besagt (grundsätzlich), dass jedes objekt nur einmal in einem programm definiert werden darf. d.h. in allen übersetzungseinheiten darf es nur eine einzige definition geben.
    die include-guards funktionieren aber nur jeweils pro übersetzungseinheit, verhindern also bloß das einbinden desselben headers in einer übersetzungseinheit, schützen dich aber nicht davor, den header in zwei oder mehr ÜEs einzubinden. wenn du jetzt in einem header eine definition eines objekts (oder einer funktion hast), das nach der ODR nur einmal definiert werden darf, und du den header in mehr als einer übersetzungseinheit einbindest, wird dir der linker einen multiple-reference, oder already-defined fehler liefern.
    beispiel:

    // header.h
    #ifndef HEADER_H
    #define HEADER_H
    
    int foo; //definition von foo
    
    #endif
    
    //one.cpp
    #include "header.h"
    
    //two.cpp
    #include "header.h"
    

    => fehler.
    deshalb dürfen in den header (in der regel) nur deklarationen. in einer übersetzungseinheit deiner wahl kommt dann die definition.

    // header.h
    #ifndef HEADER_H
    #define HEADER_H
    
    extern int foo; //dies ist eine deklaration
    
    #endif
    
    //one.cpp
    #include "header"
    
    int foo; //dies ist die definition
    
    //two.cpp
    #include "header"
    
    int main ()
    {
       foo = 42;
    }
    

    nun ist es so, dass klassen und anderes auch in mehreren übersetzungseinheiten definiert werden dürfen (unter gewissen voraussetzungen).



  • heißt das ich muss meine ganzen klassen in den header-datein jetzt mit dem schlüsselwort extern versehen oder wie muss ich das verstehen?



  • myself schrieb:

    nun ist es so, dass klassen und anderes auch in mehreren übersetzungseinheiten definiert werden dürfen (unter gewissen voraussetzungen).

    klassen darfst du mehrmals definieren (überall, wo du sie definierst, müssen sie aber - kurz gesagt - dieselbe definition haben). objekte nur einmal.


Anmelden zum Antworten