Forward Deklaration trotz include?



  • inkludiere ich nur den header wie hier:

    #include "LoadImage.h"
    
    //class LoadImage;
    
    class Client {
      public:
         Client() { m_load = new LoadImage(); }
         LoadImage *m_load;
    };
    

    bekomme ich die Fehlermeldung:
    "Fehler: ISO-C++ verbietet Deklaration von »LoadImage« ohne Typ"

    lass ich die Forward Deklaration "class LoadImage;" drinnen, kommt folgende Meldung:
    "Fehler: invalid use of undefined type »struct LoadImage«
    Fehler: forward declaration of »struct LoadImage«"

    tja, das muss doch auf die erste art funktionieren, oder? ich binde das header file ein wo die Klasse LoadImage definiert ist und somit sollte der Typ doch bekannt sein. Könnte das Problem daran liegen dass die headers teilweise von anderen auch inkludiert werden?



  • Wenn du die Definition vom Konstruktor in eine Source-Datei auslagerst, macht auch die Forward-Deklaration keine Macken mehr.



  • Ich hoffe das ist kein reales Design (ungeachtet der anderen Probleme):

    edwood schrieb:

    ...

    ...
    class Client {
      public:
         Client() { m_load = new LoadImage(); }
         LoadImage *m_load;
    };
    

    1. (wie schon erwähnt) Trennen von Deklaration (.h/.hpp) und Definition (.cpp)
    2. Ist das Absicht das jeder von außen mit dem Zeiger tun und lassen kann wies ihm passt? (Client a; delete a.m_load...).
    3. Warum new wenn es ohnehin angelegt werden soll? (Warum dann nicht einfach ein Objekt verwenden)
    4. Ich hoffe du schreibst auch einen Destruktur (wegen delete), den Kopierkonstruktor (Wegen nötiger tiefer Kopie) und Zuweisungsoperator (Wegen nötiger tiefer Kopie und löschen des vorheriegen)... Was alles unproblematischer wäre wenn du hier ein Objekt verwenden würdest...

    Okay, ein Nachteil hat das Objekt (include ausschließlich im Header möglich, wenn man nicht gerade auf das Handle-Body-Idiom [auch pImpl genannt] wechselt)...

    cu André



  • Ich vermute mal ganz stark, dass in LoadImage.h die Klasse Client verwendet wird ..... und dementsprechend da eine forward-Deklaration von Client fehlt oder gar unmäglich ist (z.B. wenn Client als Basisklasse oder Element verwendet wird).

    Gruß,

    Simon2.



  • ok, ich versuch mal die ganzen entscheidenden stellen zu posten:
    LoadImage.h:

    #include "Client.h"
    
    class Client;
    
    class LoadImage {
      public:
         LoadImage(Client *client);
      protected:
         Client *m_client;
    };
    

    LoadImage.cpp:

    #include "LoadImage.h"
    
    LoadImage::LoadImage(Client *client)
    	: m_client(client) {};
    

    Client.h:

    #include "LoadImage.h"
    
    class LoadImage;
    class Client;
    
    class Client {
      public:
         Client();	
      protected:
         LoadImage *m_load;
    };
    

    Client.cpp:

    #include "Client.h"
    Client::Client() {
       m_load = new LoadImage(this);
    }
    

    TestApp.h:

    #include "Client.h"
    
    class Client;
    
    class TestApp {
       public:
         Client *getClient() { return &m_client; }	// Fehler: »m_client« wurde in diesem Gültigkeitsbereich nicht definiert"
       protected:
         Client m_client;				// Fehler: Feld »m_client« hat unvollständigen Typen
    };
    

    Das sollten mal die entscheidenden Stellen sein. Nachdem ich jetzt den Konstruktor von Client in die Source-Datei geschrieben hab, hat der Compiler keinen Fehler diesbezgl. gemeldet, allerdings diesen hier:
    "./TestApp.h:81: Fehler: Feld »m_client« hat unvollständigen Typen
    ./TestApp.h: In member function »Client* TestApp::getClient()«:
    ./TestApp.h:45: Fehler: »m_client« wurde in diesem Gültigkeitsbereich nicht definiert"

    aja, die vielen forward deklarationen hab ich eingefügt nachdem meistens der compiler gemeint hat, dass er die funktionen eben nicht kennt, nach dem einfügen der deklarationen gabs die entsprechenden fehler nicht mehr...



  • Also ganz grundsätzlich würde ich mal sagen, dass du Header Guards einsetzen solltest.

    Also

    #ifndef XXX_H
    #define XXX_H
    ...
    #endif
    

    Siehe auch:
    http://en.wikipedia.org/wiki/Include_guard





  • hmm....ich verwende eh header guards (wollts nur hier beim posten ersparen da es sonst noch unübersichtlicher wird), von daher kanns ja gar nicht sein dass sich die header untereinander mehrmals einbinden, oder?

    ich versteh im moment nur nicht wieso m_client einen unvollständigen typen haben soll (Client), ich binde ja genau in diesem file client.h ein und mach acuh zusätzlich die forward deklaration vom typ Client, also wie gibts das dass anscheinend der Typ Client nicht erkannt wird?



  • edwood schrieb:

    ...mach acuh zusätzlich die forward deklaration vom typ Client, ...

    Die würde ich erstmal weglassen ... hilft hier sowieso nichts (weil bei einem Client-Member eine vollständige Deklaration vorliegen muss).

    Ansonsten tippe ich auf einen Fehler bei den include-guards... (Vertipper oder so).

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Die würde ich erstmal weglassen ... hilft hier sowieso nichts (weil bei einem Client-Member eine vollständige Deklaration vorliegen muss).

    das ist ja eins von den merkwürdigen problemen, wenn ich die forward deklaration weglasse kommt wieder die fehlermeldung: "ISO-C++ verbietet Deklaration von »Client« ohne Typ". was ich ja nicht versteh weil ich eh den header Client.h einbinde, somit müsste es ja reichen und der Typ "Client" bekannt sein.

    hab auch (leider) keine fehler in den guards finden können...



  • Also mich persönlich irritiert noch das:

    #include "Client.h"
    Client::Client() {
       m_load = new LoadImage(this);
    }
    

    Warum übergibs du hier einen Zeiger der Klasse selbst? (btw: da würde noch das dazu passende delete fehlen..)



  • edwood schrieb:

    Simon2 schrieb:

    Die würde ich erstmal weglassen ... hilft hier sowieso nichts (weil bei einem Client-Member eine vollständige Deklaration vorliegen muss).

    das ist ja eins von den merkwürdigen problemen, wenn ich die forward deklaration weglasse kommt wieder die fehlermeldung: "ISO-C++ verbietet Deklaration von »Client« ohne Typ". ...

    Nö ... das ist im Prinzip dieselbe Fehlermeldung bzw. hat dieselbe Ursache: Wenn der Compiler zu den Zeilen

    Client *getClient();
    // ...
    Client m_client;
    

    kommt, liegt ihm noch keine Klassendefinition von Client vor. Mit der forward-Deklaration bringst Du ihn zwar über der ersten Zeile vorläufig zum Schweigen, aber spätestens bei der zweiten geht's einfach nicht mehr weiter.

    Versuch doch mal "brute force" und kopiere den Inhalt von Client.h in die Stelle des #includes ...

    Gruß,

    Simon2.

    P.S.: Vielleicht ist auch mit Deinen include-Pfaden was schräg...



  • drakon schrieb:

    Warum übergibs du hier einen Zeiger der Klasse selbst? (btw: da würde noch das dazu passende delete fehlen..)

    wieso irritiert dich das? ich möchte in der klasse LoadImage eine Methode von Client aufrufen (z.b. m_client->methode()), ist das so unüblich? (bin aber leider nicht so der C++-Profi wie man sieht...), btw: delete mach ich eh im destruktor, aber nachdem das nichts mit meinem aktuellen problem zu tun hat hab ichs hier nicht dazu geschrieben.

    übrigens steht Client in einem eigenen Namespace (XY), könnte das zu einem Problem führen? hab aber eh überall XY::Client geschrieben, auch bei den forward deklarationen darauf geachtet: "namespace XY { class Client; }". wollts hier nicht extra dazuposten um es etwas übersichtlicher zu lassen und ich nicht da das problem vermute.



  • Meiner Meinung nach ergeben sich die Probleme schon durch den falschen Entwurf ( Konzept ).

    1. Wenn jede Klasse jede andere kennt, wozu brauchst du dann überhaupt noch verschiedene Klassen ?

    2. Sei froh, du hast hier nur 2 Klassen, die Probleme werden verzwickter je mehr Klassen involviert sind --> zyklische Inkludierungen

    Lösung :

    1. Das Image weiß nichts vom Client !
    2. Alle Aktionen gehen vom Client aus.

    PseudoCode :

    Client::Client()
    {
    m_Image = new LoadImage();
    m_Image->SetValues(...);
    }

    Gruß

    nurF



  • nurf schrieb:

    Meiner Meinung nach ergeben sich die Probleme schon durch den falschen Entwurf ( Konzept ).

    1. Wenn jede Klasse jede andere kennt, wozu brauchst du dann überhaupt noch verschiedene Klassen ?

    ok, danke, das war jetzt der hint. habs jetzt hinbekommen, hab einfach die load-image-klasse weggeschmissen und in die client klasse integriert. jetzt hab ich allerdings ne wirklich große (unübersichtliche) client-klasse aber es funktioniert, und das reicht vorerst.
    danke nochmals an die leute die mir weitergeholfen haben.



  • Das Problem war übrigens die Ringverkettung. Wenn du in beiden Headern jeweils den anderen inkludierst kann es nicht funktionieren.

    Denn er liest A ein und bekommt da ein Include auf B das ein Include auf A hat, dies aber ignoriert dank Includeguards. Nun hast du ein A bei denen nur die ersten Zeilen eingelesen wurden und ein B bei dem die Klassen aus A unbekannt sind (da er nicht soweit kam beim Parsen).

    Hätte also wohl reichen dürfen die Definitionen aus den Headern zu entfernen und mit Forward Declarations zu arbeiten.


Log in to reply