Ansammlung von Funktionen in header Datei?



  • zenturio13 schrieb:

    includeguards habe ich gemacht

    das sind diese #ifndefine _BLAH_ oder?

    ja wie soll das aussehen? ich schreibe nur funktionen ohne klassen...

    Ich mache dir aber mal ein kurzes Beispiel für eine Trennung:

    funk.h

    #if !defined(FUNK_HEADER)
    #define FUNK_HEADER
    
    namespace MyProject
    {
        int add(int a, int b);
        int sub(int a, int b);
    }
    
    #endif
    

    funk.cpp

    #include "funk.h"
    
    namespace MyProject
    {
        int add(int a, int b)
        {
            return a+b;
        }
    
        int sub(int a, int b)
        {
            return a-b;
        }
    }
    

    main.cpp

    #include <iostream>
    #include "funk.h"
    
    int main()
    {
        std::cout << "2+4=" << MyProject::add(2, 4) << std::endl;
        std::cout << "2-4=" << MyProject::sub(2, 4) << std::endl;
    }
    

    Dieses Beispiel zeigt dir auch das die Funktionen Werte zurückliefern. Wunder dich nicht über den Namespace, ich verwende eigentlich grundsätzlich Namensräume (und die Schreibweise #if !defined(...) ziehe ich #ifndef ... vor, da sie IMHO aussagekräftiger ist und eher C++ entspricht).

    zenturio13 schrieb:

    so? ich bemerkte dass ich static wieder weglassen kann. komisch?

    Wieso komisch? Wenn ich Funktionen ausschließlich im Header implementiere, so weist mich mein Compiler auch über Codedublikate hin, sofern ich den Header an mehreren Stellen includiere.

    zenturio13 schrieb:

    nur die funktion liefert immer noch kein ergebnis zurück wenn ich sie in der klasse ausführe. nur wenn ich den gesamten code der funktion in die klasse kopiere, gehts wieder. das macht mit der ansammlung von funktionen aber keinen sinn !

    Also deine Fehlerbeschreibung hat meines Erachtens nichts mit der Trennung in Funktionen zu tun, da liegt eher ein Fehler in den Funktionen oder Klassen selber vor. Wenn du mein Minibeispiel ausprobierst wirst du auch sehen das es Ergebnisse liefert.

    Aber davon mal abgesehen:

    zenturio13 schrieb:

    SDL_Surface *load_image(std::string filename)

    So eine Funktion entfinde ich schon problematisch:

    1. Wie ist die Speicherstrategie? Mit new, mit free, oder ist es gar ein Zeiger auf eine statische Variable? Anhand der Funktion sieht man ihr das nicht an.
    2. Objekte sollte man nie "by value" übergeben, lieber als konstante Referenz.

    Mögliche Alternative (mit boost):

    #include <string>
    #include <boost/shared_ptr.hpp>
    
    boost::shared_ptr<SDL_Surface> load_image(const std::string& filename) ...
    

    cu André



  • asc schrieb:

    2. Strikte Trennung von Deklaration (.h) und Definition (.cpp) - Ausnahmen sind ausschließlich Templates

    ausnahmen sind *klassen*. du meintest wohl die trennung zur implementation.
    eine klassendefinition ist bereits ohne implementation eine definition, d.h. zweimal in der selben übersetzungseinheit definieren, verstößt gegen die ODR. klassendeklarationen (forward declaration) und funktionsdeklarationen kann man so beliebig oft wie gewünscht einführen, dafür sind include guards gar nicht nötig. (in deinem (asc) letzten codebeispiel ist das zum beispiel so) - heißt natürlich nicht, dass man auf include-guards verzichten soll.

    @OP: static in diesem kontext ersetzt man durch "unnamed namespaces", um die sichtbarkeit der variable/funktion auf die aktuelle übersetzungseinheit zu beschränken. nicht, dass es dann funktioniert; aber du solltest dir ergooglen, was static hier bedeutet.



  • queer_boy schrieb:

    asc schrieb:

    2. Strikte Trennung von Deklaration (.h) und Definition (.cpp) - Ausnahmen sind ausschließlich Templates

    ausnahmen sind *klassen*. du meintest wohl die trennung zur implementation.

    Nein, ich meine was ich sage: Deklaration (dazu gehören auch Klassendeklarationen) und Definition )Implementierung). Mag sein das ich 10 Jahre lang falsche C++ Bezeichnungen verwende (und diese auch so gelernt habe).

    cu André



  • Hab grad den Thread hier gefunden, und mich wundert hier, dass folgendes funktionieren soll:

    faq.h

    int addiere(int a,int b)
    {
       return (a+b);   
    }
    

    limp.cpp

    #include <iostream>
    #include "faq.h"
    using namespace std;
    int main(void)
    {
       addiere(4,5);
       system("Pause");
    }
    

    Er findet nämilch die Funktion 'addiere' nicht. (Addiere ist ja auch schon definition)

    Zudem wundert mich, dass Klassendefinition nicht in Headerdateien gehört.
    Weil eine Deklaration wäre ja:

    class hallo;
    

    und eine Definition schon:

    class hallo
    {
       private:
          int a;´
    };
    

    Und die Definition steht bei mir immer in den Headern- das haben wir sogar in der Schule gelernt.



  • 777 schrieb:

    Hab grad den Thread hier gefunden, und mich wundert hier, dass folgendes funktionieren soll:

    faq.h

    int addiere(int a,int b)
    {
       return (a+b);   
    }
    

    limp.cpp

    #include <iostream>
    #include "faq.h"
    using namespace std;
    int main(void)
    {
       addiere(4,5);
       system("Pause");
    }
    

    Er findet nämilch die Funktion 'addiere' nicht. (Addiere ist ja auch schon definition)

    Wieso sollte er die Funktion nicht finden? Eine Definition ist auch immer eine Deklaration (umgekehrt nicht). Der Linker könnte höchstens Probleme bekommen, wenn er mehrere Dateien zusammenfassen soll, die alle die "faq.h" eingebunden haben - dann hat er plötzlich mehrere Definitionen, unter denen er auswählen kann.

    Zudem wundert mich, dass Klassendefinition nicht in Headerdateien gehört.
    Weil eine Deklaration wäre ja:

    class hallo;
    

    und eine Definition schon:

    class hallo
    {
       private:
          int a;
    };
    

    Und die Definition steht bei mir immer in den Headern- das haben wir sogar in der Schule gelernt.

    Das sind beides Deklarationen (das erste eine Forward-Deklaration der Klasse, das zweite deklariert deren Member - die Definition geschieht später (statische Member und Methoden mußt du nochmal explizit angeben, normale Member werden implizit definiert, wenn du ein Objekt dieser Klasse anlegst).



  • 777 schrieb:

    Hab grad den Thread hier gefunden, und mich wundert hier, dass folgendes funktionieren soll:

    faq.h

    int addiere(int a,int b)
    {
       return (a+b);   
    }
    

    limp.cpp

    #include <iostream>
    #include "faq.h"
    using namespace std;
    int main(void)
    {
       addiere(4,5);
       system("Pause");
    }
    

    warum sollte das nicht funktionieren? warum sollte er die definition nicht finden? nach dem durchgang des präprozessors sieht deine datei so aus:

    /* was immer in iostream steht */
    int addiere(int a,int b)
    {
       return (a+b);   
    }
    
    using namespace std;
    int main(void)
    {
       addiere(4,5);
       system("Pause");
    }
    


  • CStoll schrieb:

    Zudem wundert mich, dass Klassendefinition nicht in Headerdateien gehört.
    Weil eine Deklaration wäre ja:

    class hallo;
    

    und eine Definition schon:

    class hallo
    {
       private:
          int a;
    };
    

    Und die Definition steht bei mir immer in den Headern- das haben wir sogar in der Schule gelernt.

    Das sind beides Deklarationen (das erste eine Forward-Deklaration der Klasse, das zweite deklariert deren Member - die Definition geschieht später (statische Member und Methoden mußt du nochmal explizit angeben, normale Member werden implizit definiert, wenn du ein Objekt dieser Klasse anlegst).

    das ist eine definition. und auch für die member der klassen kann man das definition nennen (wie es der standard auch tut, und nicht bloß deklaration). nur statische member werden in einer klassendefinition bloß deklariert und müssen danach (nicht nochmal, sondern zum ersten mal) definiert werden. dein erstes beispiel class X; muss noch nichtmal eine forward-deklaration sein, es kann auch einfach eine redeklaration einer bereits definierten klasse sein.

    regel: eine deklaration _ist_ eine definition, außer (unter anderem) sie deklariert eine statische elementvariable (siehe v.a.: 3.1/2 und 3, 9.1., zu statischen membern: 9.4.2/2)



  • irgendwie hat mich das jetzt etwas durcheinander gebracht^^

    http://www.c-plusplus.net/forum/viewtopic-var-t-is-61231.html

    Dort wird ganz klar gesagt, dass Deklarieren nur heisst einen bestimmten Namen in einem Scope zu reservieren.

    extern int a;
    
    void foo(int);
    
    class hallo;
    

    Oder etwas in der Richtung.

    Definieren heisst, dass der Compiler speicher belegt.
    Also welche der Aussagen stimmt jetzt?^^

    class hallo 
    { 
       private: 
          int a; 
    };
    

    Belegt ja in dem Sinne auch noch keinen Speicher sondern gibt nur die Namen der Member der Klasse bekannt.
    Also kann letztriger Codeschnipsel doch in die Header <-- Ist also eine klare DEKLARATION?
    Doch was käme dann von der Klasse 'hallo' noch in die ausgelagerte Cpp?



  • Ja, das kann schonmal zu Verwirrungen führen. Die Klassendefinition gehört in den Header (aus technischer Sicht würde ich das auch als Deklaration ansehen), in die CPP gehört die Definition der statischen Member und Methoden (die bei dieser Klasse nicht existieren):

    //Klassen-Definition - gehört in den Header
    class test
    {
      int i;
      static int s;
    public:
      void print();
    };
    
    //Member-Definitionen - gehören in die CPP
    int test::s;
    
    void test::print()
    {
      cout<<s<<" "<<i<<endl;
    }
    
    //test::i muß nicht gesondert definiert werden - das lebt innerhalb der 'test'-Objekte, die du irgendwo im Programm anlegen kannst
    


  • Das wiederum würde aber auch bedeuten, dass alle Elementfunktionen ausgelagert werden müssen.
    Also sollte KEINE davon innerhalb der Klasse definiert werden, wie man es auch häufig im Netz sieht.
    Sondern immer mit dem Zugehörigkeitsoperator in eine andere Datei - die Cpp-Datei?

    Also wäre die Regel auch:

    Keine Elementfunktionen innerhalb der Klasse definieren.

    ?^^



  • 777 schrieb:

    Also wäre die Regel auch:

    Keine Elementfunktionen innerhalb der Klasse definieren.

    ?^^

    Nicht ganz - inline Funktionen dürfen (und müssen) im Header definiert werden (weil der Compiler den Quelltext benötigt, um sie inline ersetzen zu können). Und Methoden, die direkt in der Klassendefinition definiert werden, gelten automatisch als inline.



  • Also dürfen in den Header nur Deklarationen, mit großer Ausnahme von Inlinefunktionen? 😉
    Okay... super- ich denk ich habs verstanden xD



  • 777 schrieb:

    Definieren heisst, dass der Compiler speicher belegt.

    vielleicht könnte man diesen punkt genauer herausarbeiten als: definieren heißt, das an der stelle der definition dem compiler bekannt gemacht wird, wieviel speicher er für eine gewisse entität bereit stellen soll - was nicht heißt, dass er das auch machen muss. ein schönes beispiel dafür sind klassendefinitionen, ein anderes compiletime-konstanten, für die auch nur bei bedarf speicher reserviert wird. (wobei man sich da natürlich auf dünnem eis bewegt, der standard definiert definition als eine deklaration, bei der gewisse bedingungen nicht gegeben sind)

    und um dich nochmal zu verwirren, du kannst in einem header auch "normale" definitionen haben, ohne je probleme beim kompilieren oder linken zu bekommen, z.b.

    namespace { int i; }
    const int x = 42;
    


  • Was man kann und was man soll ist ja nochmal ein Unterschied.
    Es geht mir ja darum zu lernen, was man sollte.
    Und wenns besserer oder übersichtlicherer Programmierstil ist in die Header nur Deklarationen zu schreiben- so mach ich das 😉



  • damit wollte ich nur sagen, dass es sehr wohl auch ausnahmen geben kann. die integralkonstante ist ein gutes beispiel dafür. in den header oder nicht? nein? was ist mit enums?

    wichtig ist, die ODR zu kennen und zu wissen, was übersetzungseinheiten sind - und dass der präprozessor nur eine einfache textersetzungsmaschine ist.



  • queer_boy schrieb:

    und um dich nochmal zu verwirren, du kannst in einem header auch "normale" definitionen haben, ohne je probleme beim kompilieren oder linken zu bekommen, z.b.

    namespace { int i; }
    const int x = 42;
    

    Ja, absolut legal - und die Quelle von Verwirrungen sowohl für dich als auch für andere. (gerade beim ersteren hast du das Problem, daß jede ÜE ihre eigene Version von i bekommt (und du am Ende eine Ewigkeit auf der Suche nach dem Fehler verbringst)

    @777: Wichtig ist vor allem, daß du (a) die Regeln der Sprache (hier vor allem die ODR) einhältst und (b) sauber programmierst.

    Die ODR verbietet es, daß ein Objekt mehrfach im Programm definiert wird. Klassendefinitionen fallen nicht unter die strenge Auslegung der ODR, weil Klassen keine vollwertigen Objekte sind (sondern nur ein Bauplan für Objekte), inline-Funktionen und Templates werden vom Compiler und Linker gesondert behandelt.
    (btw, statische Variablen und anonyme namespaces bleiben lokal in ihrer Übersetzungseinheit - damit stören sie den Linker ebenfalls nicht).

    Zur sauberen Programmierung gehört es unter anderem, globale Variablen zu vermeiden - und auch sauber zwischen Schnittstelle (Deklarationen etc. im Header) und Implementation (in einem eigenen CPP) zu trennen.


Anmelden zum Antworten