C++ Klasse / Dateien



  • Hallo,
    ich weiß, die Frage kommt öfter und ich habe sie eigentlich glaube ich schon
    selber gestellt, aber jetzt wird sie wichtig, weil ich Quellcode
    veröffentlichen will (Ich bin ein ziemlicher Perfektionist! 😉 ). Also ich
    habe eine Klasse (was für ein Wunder in C++ 😃 ) und möchte jetzt wissen, wie
    ich den Code jetzt verpacken soll, heißt: soll ich alles in eine Datei
    schreiben, soll ich den Funktionskopf vom Rumpf trennen, oder zusammenlassen?

    Vielen Dank!



  • Normal kommt die Deklaration in den Header und der Code nur, wenn es inline sein soll.



  • Also eine *.cpp und eine *.h???



  • Korrekt,

    außer templates, da lohnt sich eigentlich immer inline in der Header-Datei.
    Also aufspaltung in .h und .tcc und #include "foo.tcc" am ende der Header-Datei lohnt sich imho nicht.

    Und zu .h und .cpp -> Eine Klasse pro Modul (.h+.cpp) ist *meistens* sinnvoll.

    Edit: ein "nicht" im 2. Satz hinzugefügt. 🙂



  • Was ist denn *.tcc? Hab noch nie gehört.

    Zu .h und .cpp:
    Also:

    bla.h

    // Code
    
    class bli {
    public:
       void bla();
    };
    
    // Code
    

    bla.cpp

    // Code
    
    void bli::bla() {
       // blub
    }
    
    // Code
    

    Aber in welcher Dateien soll ich was inkludieren?



  • Beispiel ohne Templates mit strikter Trennung des Moduls in .h und .cpp -Datei:

    // myclass.h
    #ifndef MYCLASS_H
    #define MYCLASS_H
    
    class MyClass {
    private:
        int m_i;
    public:
        MyClass();
        ~MyClass();
    
        void do_stuff(); // nicht inline, lohnt nich
        int get_count() const // inline sinnvoll
        {
            return m_i;
         }
    };
    
    #endif // !MYCLASS_H
    
    // myclass.cpp
    
    MyClass::MyClass()
     : m_int(0)
    {}
    
    MyClass::~MyClass()
    {}
    
    void MyClass::do_stuff()
    {
        // manch was
        m_i++;
        // mach noch mehr
    
        // hier würde zu viel stehen, als dass sich inline lohnen würde
    }
    

    nun zur *.tcc, das gehört auch eigentlich nicht standardäßig zu C++ (soweit ich weiß), aber bspw. die STL-Implementation vom gcc (libstdc++) macht es so:

    // mycontainer.h
    #ifndef MYCONTAINER_H
    #define MYCONTAINER_H
    
    template<class T>
    class MyContainer
    {
    private:
        T* m_ptr;
    public:
        MyContainer(size_t size);
        ~MyContainer();
    };
    
    // hier wird includiert
    #include "mycontainer.tcc"
    
    #endif // !MYCONTAINER_H
    
    // mycontainer.tcc
    
    template<class T>
    MyContainer::MyContainer(size_t size)
    {
        m_ptr = new T[size];
    }
    
    template<class T>
    MyContainer::~MyContainer()
    {
        delete m_ptr;
    }
    

    .tcc kannst du dir als "template c++ (implementation) file" übersetzen, die für templates die Implementation in der Header-Datei stehen muss, du sie aber trotzdem in eine extra Datei (die aber nicht dem Kompiler mitgeteilt wird!) auslagerst.

    natürlich könnte man den Ctor und Dtor beide inline direkt in die .h Datei schreiben. Könnte meistens sogar übersichtlicher sein. Ich denke, es kommt hier hauptsächlich auf den eigenen Geschmack an, weniger auf die Projektgröße. Höchstens noch die Klassengröße.



  • Aber wenn man im obieren Beispiel myclass.h in main.cpp inkludiert wird das doch
    nicht mit myclass.cpp in Verbindung gebracht. Man muss doch irgendwo die myclass.cpp
    inkludieren, oder?



  • Hä?

    Ein weiteres Trivialbeispiel mit dem von oben:

    // myclass.h
    #ifndef MYCLASS_H
    #define MYCLASS_H
    
    #include <string>
    
    class MyClass
    {
    private:
        // sichern, was zuletzt gesagt wurde
        std::string m_lastsaid; 
    public:
        MyClass();
        ~MyClass();
        void say(const std::string& s);
    
        std::string last_said() const // inline
        {
            return m_lastsaid;
        }
    };
    
    #endif // !MYCLASS_H
    
    //myclass.cpp
    #include <iostream>
    #include "myclass.h"
    
    MyClass::MyClass()
     : m_lastsaid("<nothing>") // initialisieren, keine ausgabe bisher
    {}
    
    MyClass::~MyClass()
    {}
    
    void MyClass::say(const std::string& s)
    {
        m_lastsaid = s;
        std::cout << m_lastsaid << std::endl;
    }
    
    // main.cpp
    // benutzung
    #include <iostream>
    #include "myclass.h" // eine HEADER (.h) Datei
    
    int main()
    {
        MyClass a;
    
        a.say("hello"); // hello auf dem bildschirm
        a.say("world"); // world auf dem bildschirm
        // ... letzte ausgabe?
        std::cout << a.last_said() << std::endl; // ausgabe: world
        if(a.last_said() == "hello") // false, weil letzte ausgabe world war
            std::cerr << "letzte ausgabe war nicht world"; // wird nie erreicht
    }
    

    MyClass gibt also mit MyClass::say() einen Text aus, und speichert diese letzte Meldung im std::string m_lastsaid. Es gibt eine .h und eine .cpp für die klasse und eine .cpp für int main().

    diese machst du jetzt so dem Compiler (bspw. g++ bekannt)

    g++ main.cpp myclass.cpp
    

    Eine .cpp muss nirgends inkludiert werden (!). Du machst sie entweder im Projekt deiner IDE, in deinem Makefile oder in der Kommandozeile deinem Compiler bekannt.

    Am besten schaust du mal bei Google und der (englischen) Wikipedia nach Deklaration und Definition in der Programmierung, bzw. genauer bei C++ (und nebenbei noch C, schaden wirds nich). 🙂

    Edit: schönheitsfehler



  • Also, du inkludierst im Hauptprogramm die Headerdatei. Die Funktionen an sich
    sind in der *.cpp und dort wird die Header auch inkludiert. Wie funktioniert
    denn das, dass man in der main.cpp dann auf die Funktionen zugreifen kann, wenn
    sie doch eigentlich nicht inkludiert werden? Oder wird die *.cpp immer zum
    Projekt hinzugefügt???

    Und noch eine Schönheitsfrage:
    Zu der Klasse habe ich noch ein paar Konstanten und ein Enum. Soll ich das ganze
    in einen Namespace verpacken????



  • Oh sry, hab deinen letzten Post nicht ganz durchgelesen.



  • D schrieb:

    Und noch eine Schönheitsfrage:
    Zu der Klasse habe ich noch ein paar Konstanten und ein Enum. Soll ich das ganze
    in einen Namespace verpacken????

    Wenn die Klassen, Konstanten und Enums einen logischen Bezug zu einander haben, kannst du das gut in den gleichen Namespace packen.


Anmelden zum Antworten