Klassen-Organisationsproblem



  • Hallo allerseits,

    langsam machts mich wahnsinng, also folgende Struktur:

    main.cpp:

    #include "CKlasse1.h"
    #include "CKlasse2.h"
    
    CKlasse1 Klasse1;
    CKlasse2 Klasse2;
    
    int main()
    {
        Klasse1.SagHallo();
        Klasse2.Wiederhole();
        return 0;
    }
    

    CKlasse1.h:

    #include <iostream>
    
    class CKlasse1
    {
        public:
        void SagHallo(void);
    };
    

    CKlasse1.cpp:

    #include "CKlasse1.h"
    
    void CKlasse1::SagHallo(void)
    {
        std::cout << "Hallo!\n";
        return;
    }
    

    CKlasse2.h:

    #include <iostream>
    
    extern CKlasse1 Klasse1;
    
    class CKlasse2
    {
        public:
        void Wiederhole(void);
    };
    

    CKlasse2.cpp:

    #include "CKlasse2.h"
    
    void CKlasse2::Wiederhole(void)
    {
        Klasse1.SagHallo();
        return;
    }
    

    So, jetzt heißt es in CKlasse2.h immer
    error C2146: Syntaxfehler: Fehlendes ';' vor Bezeichner 'Klasse1'

    Hilfe...

    lg Max



  • also was mir bis jetzt aufgefallen ist, eine methode die void ist, kann nix zurückgeben, und nimm auch mal das void als übergabeparameter raus.



  • In CKlasse2.cpp ist Klasse1 nicht bekannt (CKlasse1.h nicht inkludiert). Deswegen kennt der Compiler da auch dessen Memberfunktion nicht.



  • @Firefighter:

    Hey, danke für die schnelle Antwort!

    Ich hab beides gemacht, aber leider ändert sich dadurch nichts...

    lg Max



  • @Braunstein:

    Hmmm, das funktioniert ja sogar...^^

    Danke!

    lg Max



  • MaDsTyLe schrieb:

    ...

    Dennoch fehlen mir Anmerkungen zu deinen Code:
    * Globale Variablen sollte man vermeiden
    * Includes nur an Stellen wo man sie braucht
    * return; in einer void-Funktion/Methode als letzte Anweisung ist unnötig
    * int main() macht am Schluß (Ausnahme von der Regel) ein implizites return 0, so das du dir das Sparen kannst.
    * Ungarische Notation und ähnliches (z.B. C vor Klassennamen) ist in C++ spätestens seit der Einführung von Templates weitgehend aus der Mode geraten. Zumal man dabei in Namenskonflikte mit Bibliotheken wie der MFC oder ähnlichen kommen kann (hier würden aber Namensräume weiterhelfen).
    * (void) ist eigendlich unnötig, () sagt imho mehr aus. Dies ist aber nun wirklich Geschmackssache ;p

    (auf Includeguards etc. habe ich hier der Übersicht halber verzichtet)
    // Änderung an main.cpp:

    #include "CKlasse1.h"
    #include "CKlasse2.h"
    
    int main()
    {
        CKlasse1 Klasse1;
        CKlasse2 Klasse2(Klasse1);
        Klasse1.SagHallo();
        Klasse2.Wiederhole();
    }
    

    // Änderung CKlasse2.h:

    class CKlasse1;
    
    class CKlasse2
    {
        private:
          CKlasse1& klasse1;
        public:
          CKlasse2(CKlasse1& klasse1);
          void Wiederhole();
    };
    

    // Änderung CKlasse2.cpp:

    #include "CKlasse1.h"
    #include "CKlasse2.h"
    
    CKlasse2::CKlasse2(CKlasse1& klasse1)
    : klasse1(klasse1)
    {
    }
    
    void CKlasse2::Wiederhole()
    {
        klasse1.SagHallo();
    }
    

    cu André



  • Hmm danke, ich versteh zwar nich wieso ich globale Variablen vermeiden sollte, aber ansonsten werd ich mich bemühen Deinen Ratschlägen folge zu leisten.

    Wenn ich zB die hInstance von WinMain in eine globale Variable kopiere, kann ich sie in allen weiteren Codesegmenten sofort aufrufen und muss sie nicht immer als Parameter mitliefern. Es hilft mir schlicht und ich seh nicht, wo das Probleme bereitet.

    Egal, ich hab da noch eine Frage bezüglich der Includes.

    Wenn ich jetzt in meiner main.cpp eine global.h include, dann komm ich logischerweise aus der CKlasse2.cpp da nicht ran. Wenn ich sie da nun aber ebenfalls includiere, bekomm ich korrekterweise den Linker-Error, dass die Prozeduren nun doppelt sind.

    Wie komm ich aber trotzdem in der CKlasse2.cpp an meine global.h-Funktionen?

    lg Max



  • MaDsTyLe schrieb:

    Wenn ich jetzt in meiner main.cpp eine global.h include, dann komm ich logischerweise aus der CKlasse2.cpp da nicht ran. Wenn ich sie da nun aber ebenfalls includiere, bekomm ich korrekterweise den Linker-Error, dass die Prozeduren nun doppelt sind.

    Sauber Trennung Header und Source vorausgesetzt, wird es wohl an fehlenden Includeguards liegen...

    #if !defined(EINDEUTIGERNAME_HEADER)
    #define EINDEUTIGERNAME_HEADER
    // <-- Hier der eigentliche Includeinhalt
    #endif
    

    MaDsTyLe schrieb:

    Hmm danke, ich versteh zwar nich wieso ich globale Variablen vermeiden sollte, aber ansonsten werd ich mich bemühen Deinen Ratschlägen folge zu leisten.

    Wenn ich zB die hInstance von WinMain in eine globale Variable kopiere, kann ich sie in allen weiteren Codesegmenten sofort aufrufen und muss sie nicht immer als Parameter mitliefern. Es hilft mir schlicht und ich seh nicht, wo das Probleme bereitet.

    1. Ist die Reihenfolge der initialisierung globaler Variablen nicht definiert (Spätestens mit Abhängigkeiten untereinander kannst du dort leicht auf Fehler stoßen die schwer zu finden sind).

    2. Globale Variablen machen dein Programm schwerer zu lesen, wer worauf zugreift ist schwer zu kontrollieren.
    Ein Merkmal von sauberer Programmierung ist, das Eingangs- und Ausgangsgrößen klar erkennbar sind (Bei Funktionen über den Rückgabewert und die Parameterliste, bei Klassen über die Schnittstelle (sprich: öffentliche Methoden - öffentliche Methoden wiederum sind in der Regel ein Zeichen schlechter OO-Programmierung).

    siehe auch: http://fara.cs.uni-potsdam.de/~kaufmann//faqs/Global.pdf

    Ich rezitiere mal: "So lokal wie möglich, so global wie nötig"

    Ja, es gibt Ausnahmen in denen sie Sinn machen können, wobei es auch hier noch Alternativen gibt die zumindestens ein wenig besser sind. Aber dies sollte immer die absolute Ausnahme, nicht die Regel darstellen.

    Wenn du schon etwas "global" brauchst, kannst du wenigstens für eine definierte Initialisierungsreihenfolge sorgen:

    static Application& GetApplication()
    {
      static Application applic;
      return applic;
    }
    

    Damit ist zumindestens Sichergestellt das dieses Objekt erst mit dem ersten Aufruf initialisiert wird. Auch diese Variante beachtet nicht das Open-Closed-Prinzip, ist aber zumindest einen kleinen Tick besser als globale Objekte.

    cu André


Anmelden zum Antworten