Aufteilung auf mehrere Dateien



  • Guten Abend,

    kennt wer ein gutes Tutorial/E-Book zu dem oben genannten Thema. Am besten mit pure virtual-Klassen.
    Ich hab nämlich das Problem, dass wenn ich sämtliche pure virtual- und Implementierungsklassen in einer Datei anlege, keine Probleme damit habe.
    Die Aufteilung in Header- und Cpp-Dateien bereitet mir dagegen noch ein wenig Kopfschmerzen.

    Gruß



  • Also du meinst das du die Klasse z.B. in eine Header Datei schreibst und die Definition der Klasse, also die ganzen Funktionen, in eine Cpp schreibst?



  • Ich mach mal ein Beispiel. Hier ist alles in einer cpp-Datei und das funktioniert ohne Probleme:

    #include<iostream>
        #include<string>
        using namespace std;
    
        class BaseFormat
        {
        public:
          virtual ~BaseFormat() {}
          virtual void header() = 0;
          virtual void text(string const&, string const&) = 0;
          virtual void footer() = 0;
        };
    
        class CSVFormat : public BaseFormat
        {
        public:
          void header()
          {
          }
    
          void text(string const& name, string const& value)
          {
            cout<<<name<<';'<<value<<'\n';
          }
    
          void footer()
          {
          }
        };
    
        int main()
        {
          BaseFormat* frmt=new CSVFormat();
          frmt->header();
          frmt->text("Variable1", "Value1");
          frmt->text("Variable2", "Value2");
          frmt->text("Variable3", "Value3");
          frmt->footer();
          delete frmt;
        }
    

    Nun hatte ichs so aufgeteilt:
    BaseFormat.h:

    #include<string>
        using namespace std;
    class BaseFormat
        {
        public:
          virtual ~BaseFormat() {}
          virtual void header() = 0;
          virtual void text(string const&, string const&) = 0;
          virtual void footer() = 0;
        };
    

    CSVFormat.cpp:

    #include<iostream>
        #include<string>
    	#include "BaseFormat.h"
        using namespace std;
        class CSVFormat : public BaseFormat
        {
        public:
          void header()
          {
          }
    
          void text(string const& name, string const& value)
          {
            cout<<name<<';'<<value<<'\n';
          }
    
          void footer()
          {
          }
        };
    

    Hauptprogramm.cpp:

    #include<iostream>
        #include<string>
    	#include "BaseFormat.h"
        using namespace std;
    
        int main()
        {
          BaseFormat* frmt=new CSVFormat();
          frmt->header();
          frmt->text("Variable1", "Value1");
          frmt->text("Variable2", "Value2");
          frmt->text("Variable3", "Value3");
          frmt->footer();
          delete frmt;
        }
    

    Diese Zeile ist problematisch: BaseFormat* frmt=new CSVFormat();
    Die Fehlermeldung: parse error before `('

    Leider bringt mich das nicht wirklich weiter.

    Deswegen such ich ein Tutorial, was sich mit solch einer Thematik auseinandersetzt. Denn ich würde schon gerne die Vorteile der OOP ausnutzen wollen.
    Das Ganze würde mehr Struktur in die Sache bringen.



  • Fenixx schrieb:

    Das Ganze würde mehr Struktur in die Sache bringen.

    Da hast du recht. Aber ein Tutorial, was sich ausschließlich damit beschäftigt oder sich etwas drauf spezialisiert und weit drauf eingeht, fällt mir jetzt nicht ein, aber ich denke wir können dir auch im Forum helfen. Also sag ich jetzt mal was zu deinem Code.
    Da fällt mir als erstes folgendes auf:

    BaseFormat.h

    #include<string>
        using namespace std;
    class BaseFormat
        {
            ...
        };
    

    Du inkludierst in dieser Datei die Datei "string" und nutzt den Namensraum std. Vorweg, in Headerdateien keine Namensräume nutzen. Nun gehts weiter zu einer Cpp Datei.

    CSVFormat.cpp

    #include<iostream>
        #include<string>
        #include "BaseFormat.h"
        using namespace std;
        class CSVFormat : public BaseFormat
        {
            ...
        };
    

    Dadurch, das du in der Datei "CSVFormat.cpp" die Datei "BaseFormat.h" inkludierst, inkludierst du automatisch die Datei "string" die in "BaseFormat.h" ist, denn alles was in "BaseFormat.h" ist, wird nun in "CSVFormat.h" verwendet, einschließlich den inkludierten Dateien. Das heisst, du solltest nur in eine Datei "string" inkludieren, oder es vermeiden das "string" 2 Mal inkludiert wird. So als nächstes solltest du dich über IncludeGuards erkundigen, denn die wirst du brauchen um Multipledefinitions zuvermeiden.
    Sollten noch fragen offen sein, darfste die gerne schreiben.

    fy



  • Ich habs mal dagehend geändert:
    BaseFormat.h:

    #ifndef BaseFormat_H_INCLUDED
    #include<string>
    using namespace std;
    #define BaseFormat_H_INCLUDED
    class BaseFormat
        {
        public:
          virtual ~BaseFormat() {}
          virtual void header() = 0;
          virtual void text(string const&, string const&) = 0;
          virtual void footer() = 0;
        };
    #endif
    

    Eine Frage: Wenn ich in meiner Methodendeklaration einen String übergeben bekommen möchte, dann bleibt mir doch keine andere Wahl, als <string> zu inkludieren oder?

    CSVFormat.cpp:
    #include "BaseFormat.h"
    class CSVFormat : public BaseFormat
    {
    public:
    void header()
    {
    }

    void text(string const& name, string const& value)
    {
    cout<<name<<';'<<value<<'\n';
    }

    void footer()
    {
    }
    };
    #endif[/cpp]

    Nun habe ich den Fehler, dass der Kompiler meint, dass in "CSVFormat.cpp" cout undeclared ist.
    Die Erweiterung um

    #include<string>
    using namespace std;
    

    Führt wieder zum alten Fehler.



  • Das ist klar das cout undeclared ist, da du std nicht benutzt. Also wird

    cout << "hallo";
    

    Zu

    std::cout << "hallo";
    

    Denn durch das using namespace std; fällt das "std::" ja weg. Und mit deinem String problem, bei meiner IDE brauch ich "string" nicht zu inkludieren wenn ich "iostream" schon inkludiert hab und ich benutze Code::Blocks. Aber die Antwort auf dein Problem, wenn du string inkludiert hast, z.B. durch eine andere Datei, brauchst du die auch nicht in deiner Datei zu inkludieren.



  • FreakY<3Cpp schrieb:

    Und mit deinem String problem, bei meiner IDE brauch ich "string" nicht zu inkludieren wenn ich "iostream" schon inkludiert hab und ich benutze Code::Blocks.

    Das ist aber sehr compilerabhängig, darauf verlassen sollte man sich nicht. Wenn man std::string verwendet, inkludiert man normalerweise den Header <string> .



  • Nexus schrieb:

    ...

    Hatte ich ja auch gemeint, dass es bei meinem Compiler ist und hab ihm dann die Alternative genannt.



  • Hmm,

    ich verwende das C++-Plugin von Eclipse.
    Bei mir wird sogar als Fehler angezeigt, wenn ich in "BaseFormat.h" nicht

    using namespace std;
    

    angebe.

    Zurück zu dem ursprünglichen Problem: Hast du vielleicht noch einen Tipp, wo der Fehler in der Aufteilung der Dateien sein könnte?



  • Fenixx schrieb:

    Zurück zu dem ursprünglichen Problem: Hast du vielleicht noch einen Tipp, wo der Fehler in der Aufteilung der Dateien sein könnte?

    Inwiefern in der Aufteilung ? Also zu dem using namespace std habe ich nur gemeint, dass du es nicht in header Dateien verwenden sollst, in einer Cpp Datei ist dir freie Wahl gestattet. Was genau meinst du mit der Aufteilung ? Meint der Compiler etwas ist nicht deklariert, oder öfters deklariert, Fehlermeldungen würden mir helfen.



  • Das komische ist ja:

    #ifndef BaseFormat_H_INCLUDED
    #include<iostream>
    using namespace std;
    #define BaseFormat_H_INCLUDED
    class BaseFormat
        {
        public:
          virtual ~BaseFormat() {}
          virtual void header() = 0;
          virtual void text(string const&, string const&) = 0;
          virtual void footer() = 0;
        };
    #endif
    

    -> Kein Fehler in der Datei. Nimm ich nun den namespace raus, wird bei mir folgende Fehlermeldung angezeigt:

    parse error before 'const'
    

    😕

    Was ich mit dem ursprünglichen Problem meine:
    Zuerst habe ich ja alle Klassen und einschließlich der Verwendung in einer cpp-Datei verfasst. Das lief ohne Probleme.
    Wenn ich die Aufteilung in mehrere Dateien vornehme, habe ich die Fehlermeldung in meinem Hauptprogramm (siehe Post #3 des Threads):
    Diese Zeile ist problematisch: BaseFormat* frmt=new CSVFormat();
    Die Fehlermeldung: parse error before `('



  • Hast du den Namensraum std:: immer noch nicht angegeben?



  • Der Namespace std ist doch angegeben:
    In der BaseFormat.h:

    #ifndef BaseFormat_H_INCLUDED
    #include <string>
    using namespace std;
    #define BaseFormat_H_INCLUDED
    class BaseFormat
        {
        public:
          virtual ~BaseFormat() {}
          virtual void header() = 0;
          virtual void text(string const&, string const&) = 0;
          virtual void footer() = 0;
        };
    #endif
    

    Wenn ich using namespace std; hier in dieser Datei nicht angebe, erhalte ich folgenden Fehler:
    parse error before 'const'

    Oder was meinst du genau?



  • virtual void text(string const&, string const&) = 0;
    

    zu

    virtual void text(std::string const&, std::string const&) = 0;
    

    Zu deinem anderem Problem. Wie willst du eine Variable von einem bestimmten Typ erstellen, ohne das der Typ bekannt ist? Du hast in der main nur BaseFormat.h inkludiert und die BaseFormat.h hat keine CSVFormat.cpp inkludiert. Das heisst in deinem Programm ist die Datei CSVFormat.cpp nutzlos und "existiert" garnicht.
    Also nimmst das "#include "BaseFormat.h" aus der main raus und ersetze es mit "#include CSVFormat.cpp", wobei man Cpp Dateien eigentlich nicht inkludiert, also erstell eine "CSVFormat.h", schreib dort die Klasse rein und in die Cpp definierst du die Funktionen.

    fy



  • Danke für eure Hilfe. Wieder was gelernt 🙂 .

    Gruß



  • Hallo Fenixx,

    man sollte für jede Klasse eine eigene Header (.h/.hpp) und eine Source (.cpp) Verwenden.

    z.B.
    KLASSE1.h

    #ifndef KLASSE1_H
    #define KLASSE1_H
    #include <string>
    
    class KLASSE1 {
        public:
          virtual void text([b]std::[/b]string const&);
          //....
    };
    
    #endif //KLASSE1_H
    

    KLASSE1.cpp

    #include "KLASSE1.h"
    
    using namespace std;
    
    //Hier kommt die Definition der Funktionen der Klasse
    virtual void [b]KLASSE1::[/b]text(string const&){    //std::  kann man weglassen, da ja [i]using namespace std[/i]
        //....
    };
    

Log in to reply