Kleines Problem mit Code::Blocks und ausgelagerten Klassen



  • Hallo,

    ich habe eine Beispielklasse einmal in zwei externe Dateien ausgelagert:

    // main.cpp
    #include <iostream>
    using namespace std;
    
    #include "classtest.cpp"
    
    int main()
    {
        cout << "Hello world!" << endl;
        return 0;
    }
    
    // classtest.cpp
    #include "classtest.hpp"
    
    int EineKlasse::eineFunktion(int x)
    {
      //Anweisungen;
      return 0;
    }
    
    // classtest.hpp
    class EineKlasse
    {
      public:
        int eineFunktion(int x=42);
    
      private:
        int m_eineVariable;
    };
    

    Von Code::Blocks (bzw. von Mingw32) bekomme ich folgende Fehler:

    obj\Debug\classtest.o||In function `_ZN10EineKlasse12eineFunktionEi':|
    D:\workspace\test\classtest.cpp|4|multiple definition of `EineKlasse::eineFunktion(int)'|
    obj\Debug\main.o:D:\workspace\test\classtest.cpp|4|first defined here|
    ||=== Build finished: 2 errors, 0 warnings ===|
    

    Warum bekomme ich einen multiple definition error? Ich include die Dateien ja nicht 2x.

    Vielen Dank,
    Blu-Ray



  • Du sollst keine .cpp-Dateien inkludieren. Eher Header.



  • Aber wenn ich die .hpp include, habe ich zwar den Aufbau der Klasse, aber nicht die Funktionen includet.

    Wenn ich den hier mache:

    // classtest.hpp
    #include "classtest.cpp"
    
    class EineKlasse
    {
      public:
        int eineFunktion(int x=42);
    
      private:
        int m_eineVariable;
    };
    

    dann ist die Klasse ja noch nicht deklariert.



  • Blu-Ray schrieb:

    Aber wenn ich die .hpp include, habe ich zwar den Aufbau der Klasse, aber nicht die Funktionen includet.

    Wenn ich den hier mache:

    // classtest.hpp
    #include "classtest.cpp" //<----------
    

    Doch.

    Blu-Ray schrieb:

    dann ist die Klasse ja noch nicht deklariert.

    Das ist die Deklaration. Google nach Deklaration und Definition und erkenn den unterschied.



  • Nochmal die Files:

    // main.cpp
    #include <iostream>
    using namespace std;
    
    #include "classtest.hpp"
    
    int main()
    {
        cout << "Hello world!" << endl;
        return 0;
    }
    
    // classtest.cpp
    #include "classtest.hpp"
    
    int EineKlasse::eineFunktion(int x)
    {
      //Anweisungen;
      return 0;
    }
    
    // classtest.hpp
    #include "classtest.cpp" // <-- An dieser Stelle ist die Klasse noch nicht deklariert, das geschieht eine Zeile tiefer
    class EineKlasse
    {
      public:
        int eineFunktion(int x=42);
    
      private:
        int m_eineVariable;
    };
    

    In der classtest.cpp werden die Funktionen ja schon definiert, während es die Klasse noch nicht gibt. Das hatte ich gemeint.

    B2T: Wie "verknüpfe" ich die Klassen jetzt miteinander, ohne dass ich die obengenannten Fehler bekomme?



  • Blu-Ray schrieb:

    In der classtest.cpp werden die Funktionen ja schon definiert, während es die Klasse noch nicht gibt. Das hatte ich gemeint.

    Natürlich gibt es die Klasse an der Stelle schon, schließlich inkludierst du die classtest.hpp, in der die Klasse definiert wird.

    Blu-Ray schrieb:

    B2T: Wie "verknüpfe" ich die Klassen jetzt miteinander, ohne dass ich die obengenannten Fehler bekomme?

    Du mußt in jedem Fall das #include "classtest.cpp" aus der classtest.hpp rausnehmen. cpp-Dateien inkludiert man im Allgemeinen nicht, und es gibt hier auch keinen Grund, das zu tun.

    Und dann such mal nach "Include Guards", die wirst du hier nämlich brauchen.



  • Wenn ich jetzt die .hpp Datei in die main.cpp include, habe ich ja nur die Struktur der Klasse inkludiert. Wie kann ich jetzt noch die Funktion eineFunktion beschreiben?



  • Blu-Ray schrieb:

    Wenn ich jetzt die .hpp Datei in die main.cpp include, habe ich ja nur die Struktur der Klasse inkludiert. Wie kann ich jetzt noch die Funktion eineFunktion beschreiben?

    Was meinst du denn mit "beschreiben"?

    In C++ unterscheidet man zwischen Deklarationen und Definitionen. Eine Deklaration sagt in etwa "es gibt eine Funktion, die heißt Soundso, und hat die und die Parameter". Das ist die Zeile int eineFunktion(int x=42) in deiner classtest.hpp.
    Eine Definition hingegen sagt "die Funktion Soundso macht folgendes...". Das ist das, was in deiner classtest.cpp steht.

    Um die Funktion aus der main.cpp heraus aufrufen zu können, muß der Compiler nur wissen, daß es die Funktion gibt, d.h. er braucht die Deklaration. Dafür, daß dann auch später die richtige Funktion aufgerufen wird, sorgt der Linker, wenn er aus main.o und classtest.o das fertige Binary zusammenbaut.



  • In der classtest.hpp deklariere ich ja die Klasse. Wenn ich aber vor der Deklaration (Zeile 2 in der classtest.hpp) die Definition include (classtest.cpp), "existiert" die Klasse ja noch gar nicht, weil sie erst später deklariert wird.

    Wie kann ich jetzt die Klassendeklaration und die -definition in zwei verschiedene Dateien auslagern, ohne dass Fehler auftreten?



  • Nur damit Begriffe klar werden:

    // Das ist eine Klassendefinition (und zusätzlich eine Deklaration).
    class MyClass
    {
    
    };
    
    // Das hingegen ist nur eine Klassendeklaration (Forward Declaration).
    class MyClass;
    

    Aber zu deinem Problem. Du brauchst die Definitionen der Funktionen für die Klassendefinition nicht einzubinden. Das geschieht alles auf Linker-Ebene. Üblich ist, die Klasse in einer .h/.hpp- und einer .cpp-Datei vollständig zu implementieren. In Dateien, die die Klasse verwendest, kannst du den Header der Klasse inkludieren, somit hast du die ganze Funktionalität. Hier mal ein Beispiel zur Verdeutlichung, stell bei Unklarheiten einfach Fragen:

    // -----------------------------------------------------
    // MyClass.hpp - Klassendefinition, Methodendeklaration
    class MyClass
    {
        private:
            int MyVar;
        public:
            MyClass(int Var = 0);
            void SetVar(int Var);
            int GetVar() const;
    };
    
    // -----------------------------------------------------
    // MyClass.cpp - Methodendefinition
    #include "MyClass.hpp"
    
    MyClass::MyClass(int Var)
    : MyVar(Var)
    {
    }
    
    void MyClass::SetVar(int Var)
    {
        MyVar = Var;
    }
    
    int MyClass::GetVar() const
    {
        return MyVar;
    }
    
    // -----------------------------------------------------
    // Main.cpp - Verwendung der Klasse und deren Methoden
    #include "MyClass.hpp"
    
    int main()
    {
        MyClass a;
        MyClass b(5);
    
        a.SetVar(7 * b.GetVar());
    }
    


  • Blu-Ray schrieb:

    // classtest.hpp
    #include "classtest.cpp" //wofür inkludierste die cpp Oo? was will die klasse mit den funktionen
    class EineKlasse
    {
      public:
        int eineFunktion(int x=42);
    
      private:
        int m_eineVariable;
    };
    


  • Nexus schrieb:

    Du brauchst die Definitionen der Funktionen für die Klassendefinition nicht einzubinden. Das geschieht alles auf Linker-Ebene. Üblich ist, die Klasse in einer .h/.hpp- und einer .cpp-Datei vollständig zu implementieren. In Dateien, die die Klasse verwendest, kannst du den Header der Klasse inkludieren, somit hast du die ganze Funktionalität

    Danke, diese Information hat mir gefehlt.


Anmelden zum Antworten