Zwei voneinander abhängige Klassen => Undefinierte Bezeichnungen



  • Hallo Community,

    das ist hier meine erste Frage zu einem programmiertechnischen Problem mit C++. Bisher habe ich mit dieser Sprache vielerlei Erfahrungen auf mehreren Entwicklungsumgebungen gemacht, weshalb alles auch soweit mehr oder minder gut lief. Heute arbeite ich viel mit Eclipse und bin nun auf folgendes Problem gestoßen:

    Ich habe zwei Klassen mit den Namen KlasseA und KlasseB in eigenen Header-Dateien angelegt, die jeweils getrennt kompiliert werden. D.h. einmal wird "KlasseA.h" kompiliert und einmal "KlasseB.h". Soweit so gut: Jetzt sind aber beide Klassen - wie die nachfolgenden Beispiele anschaulich machen - voneinander abhängig. Damit meine ich, dass z.B. Datentypen, die innerhalb des Namensraumes der einen Klasse vorhanden sind, auch von der anderen Klasse verwendet werden.

    KlasseA.h:

    #ifndef _KLASSEA_H_
    #define _KLASSEA_H_
    
    /* Weil auch "KlasseB.h" KlasseA verwendet, wie auch
     * "KlasseA.h" KlasseB, muss ich sie vordefinieren, was bisher
     * wie folgt funktioniert hat:
     */
    
    class KlasseA;
    
    /* Erst jetzt darf die Einbindung von "KlasseB.h" erfolgen: */
    
    #include "KlasseB.h"
    
    class KlasseA
    {
    public:
      typedef void IrgendeinTyp;
      class IrgendeineKlasse{ ... };
      // ...
      void Funktion(KlasseB X); // Hier wird die andere Klasse verwendet.
    
    }; /* class KlasseA */
    
    #endif
    

    KlasseB.h:

    #ifndef _KLASSEB_H_
    #define _KLASSEB_H_
    
    class KlasseB;
    
    #include "KlasseA.h"
    
    class KlasseB
    {
    public:
      // ...
    
      void Funktion(KlasseA::IrgendeinTyp X, KlasseA::IrgendeineKlasse Y); //Hier erfolgt ein Fehler
    
      /* Denn KlasseA ist zwar bekannt,
       * jedoch nicht KlasseA::IrgendeinTyp und
       * KlasseA::IrgendeineKlasse.
       */
    
    }; /* class KlasseB */
    
    #endif
    

    Zwar konnte ich bisher Klassen vordefinieren, ohne dass mir der Kompiler die Meldung "Redefinition of..." ausgibt, doch bei Klassen in Klassen und anderen Bezeichnungen innerhalb einer Klasse finde ich keinen Weg, auch diese Dinge vorzudefinieren.

    Die Frage ist also: Wie kann ich zwei voneinander abhängige aber getrennt kompilierte Klassen aneinander vollständig bekannt machen.

    Falls ihr Euch selbst fragt, wieso ich alle Dateien einzeln kompiliere, anstatt nur eine von beiden: Eclipse macht das irgendwie automatisch und den Nutzen dahinter habe ich offen gesagt noch nicht wirklich begriffen. Das spielt aber auch keine Rolle, da das Problem genauso auftritt, wenn ich nur eine der beiden Dateien kompiliere.

    Vielen Dank im Voraus
    Gruß Josef



  • Hallo!

    Willkommmen im Forum! Auf den ersten Blick sehe ich nichts, was dagegen spricht, KlasseB in KlasseA.h vorwärtszudeklarierern, da du die Funktion ja offenbar in einer .cpp-Datei implementierst. Generell ist es oft ratsam, die Implementierungen von Funktionen in .cpp's auszulagern, um möglicherweise auch Abhängigkeiten zu reduzieren.

    Dass jede Date einzeln kompiliert wird, liegt nicht an Eclipse, sondern an daran, dass Eclipse makefiles verwendet, um das Projekt zu erstellen. Der Sinn davon ist, nur Dateien neu zu kompilieren, die geändert wurden.

    Übrigens, falls du deine Include-Guards alle mit einem Underscore anfangen lässt, solltest du das lieber bleiben lassen, da Bezeichner, die mit einem Underscore und einem Großbuchstaben vom C++-Standard her für die Implementierung reserviert sind.

    Grüße,
    Der Kellerautomat



  • In KlasseA brauchst du nur eine Vorwärtsdeklaration von Klasse B. D.h. hör auf, dort KlasseB.h zu inkludieren. Und schreib nicht die Vorwärtsdeklaration der Klasse vor das Include, das sie benötigt, denn wenn die Datei irgendwo anders eingebunden wird, ist die Vorwärtsdeklaration vielleicht nicht mehr da. Schreib sie lieber gleich in die Datei.



  • Erstmal danke für eure Hilfe und für ein bisschen Allgemeinwissen (Stichwort "Include-Guards" usw.).

    Zur Vorwärtsdeklaration: In der Tat ist es auch einfach möglich, in "KlasseA.h" einfach KlasseB zu deklarieren, anstatt gleich die ganze Header-Datei zu inkludieren.

    Nehmen wir nun aber an, dass KlasseB wie folgt aussieht:

    class KlasseB
    {
    public:
      typedef void NochIrgendeinTyp; //<- das hier kommt nun hinzu
    
      ...
    
      void Funktion(KlasseA::IrgendeinTyp X, KlasseA::IrgendeineKlasse Y);
    };
    

    und KlasseA würde irgendwo den Typ "KlasseB::NochIrgendeinTyp" verwenden, dann ginge das offensichtlich schief, da für KlasseA zwar die Bezeichnung KlasseB bekannt ist, weitere Bezeichner wie "KlasseB::NochIrgendeinTyp" jedoch nicht.

    Deswegen meine Frage, wie man zwei Klassen aneinander vollständig bekannt machen kann.

    Gruß Josef



  • pureprogger schrieb:

    Deswegen meine Frage, wie man zwei Klassen aneinander vollständig bekannt machen kann.

    Soweit ich weiß gar nicht. Du musst deine typedefs wohl irgendwie anders machen.



  • ...und genau das habe ich befürchtet und hier zu beantworten versucht. Nun, dann muss ich mich irgendwie anders behelfen. Trotzdem danke 🙂



  • Du könntest als Workaround eine Templte-Klasse machen, die den Typ deiner Klasse erhält und dann von dieser Templte-Klasse auf deine Klasse A und B erben lassen.

    ...
    class B : public TypeClass< B >
    {
    ...
    };
    

    MfG



  • Vielen Dank für den Tipp yihaaa, auch wenn ich zu den perfektionistischen Systematikern gehöre, die aus Ärgernis über die Beschränktheit einer Programmiersprache getrost auf Workarounds verzichten und sich aus Frust eine eigene Programmiersprache basteln wollen. :p



  • Das hat mit Beschänkungen nichts zu tun sondern mit der Art, wie #include funktioniert. Für alles gibt es Lösungen, und wenn du mit "nehmen wir mal an" kommst, ohne deinen konkreten Code zu zeigen, kann man dir nicht helfen. Für den Code im Startpost wurde dir bereits eine simple Lösung genannt.


Anmelden zum Antworten