Forward declaration & header inclusion

  • Hallo Leute..
    Hab folgendes Problem: Mir ist nicht ganz klar wann ich forward declaration und wann header inclusion einsetzen sollte. Weiss wer da die geneuen Regeln fuer *.cpp und *.h files?

    Auf jeden Fall bekomme ich 'nen compile error "C2027: use of undefined type 'Type'" bei folgendem Aufbau:

    Haengt die Fehlermeldung mit der forward declaration zusammen?

    Dank im Voraus fuer jede Hilfe..
    ciao..

  • Sorry, war nur ein Tippfehler (hab's oben ausgebessert). Trotzdem danke, hast natuerlich Recht, aber das obige Problem besteht immer noch..

    ciao..

  • Jou, das Schlüsselwort ist "fully defined" (OK, sind zwei Wörter ;) ). Der Compiler kann keinen Code für Klasse B erzeugen, solange er nicht Klasse A kennt; z.B. wird die Größe von Klasse A für Feld- und Methodenzugriffe gebraucht, und für Konstruktoren muß bekannt sein, wie ein A konstruiert werden muß und so. Also die forward declaration muß auch durch eine tatsächliche Definition von A ergänzt werden.

    *plantsch*

  • Zitat von lerod

    hm erstens einmal versteh i ned, warum/weshalb auch immer bei dir class B 2x definiert wird. egal, jedenfalls lt MSDN: http://msdn.microsoft.com/library/defaul…/html/C2027.asp

    Sorry, hab's auf die Schnelle gepostet und nicht ueberprueft.. Jetzt muesste es stimmen.. sorry das Wirrwarr..

    Zitat von Plantschkuh!

    Jou, das Schlüsselwort ist "fully defined" (OK, sind zwei Wörter ). Der Compiler kann keinen Code für Klasse B erzeugen, solange er nicht Klasse A kennt; z.B. wird die Größe von Klasse A für Feld- und Methodenzugriffe gebraucht, und für Konstruktoren muß bekannt sein, wie ein A konstruiert werden muß und so. Also die forward declaration muß auch durch eine tatsächliche Definition von A ergänzt werden.

    Danke sehr.. Hab jetzt den Code geaendert (siehe Post #1), aber das was du sagst, trifft auch auf den zu. Ich hab also A,B,C sowohl deklariert (*.h) als auch definiert (*.cpp). Sobald ich aber versuche, eine Forward Declaration von B im File file_a.h zu machen, schreit er, und verlangt eine Definition von B.. Der Fehler tritt aber im File file_b.cpp auf (siehe Post #1: C2027).

    Ich weiss nicht, wieso er von der Definition von B nichts weiss. Irgendwelche Ideen?

    Danke nochmals..
    ciao..

  • hm also momentan seh i sowieso ned ganz ein, wieso du nicht folgendes machen kannst (?!)


    //////////////
    // file_a.h

    #include "file_b.h"
    #include "file_c.h"

    class A : public C
    {
    B *myvar_;
    ...
    };

  • Ja, also das hab ich vorher auch gehabt (ohne forward declaration). Ich bin dann auf einer Seite (http://www-subatech.in2p3.fr/~photons/subat…CPP-INC-1.shtml) gestoszen, wo diese Methode propagiert wird und dachte mir, dass ich meinen Code auch abaendern sollte. Aber ich glaub', ich belasse es bei der Variante die du vorgeschlagen hast.. da geht's und ich finde, dass es so uebersichtlicher ist.

    Danke auf jeden Fall..
    ciao..

  • Hast du in file_a.cpp die Headerdatei file_b.h inkludiert?

    Viele Menschen sind zu gut erzogen, um mit vollem Mund zu sprechen,
    aber sie haben keine Scheu, es mit leerem Kopf zu tun.
    (Orson Welles)

  • Zitat von Bug

    Hast du in file_a.cpp die Headerdatei file_b.h inkludiert?

    Ja, also fuer gewoehnlich inkludiere ich die Header-Dateien sowohl in *.cpp als auch in *.h-Files.. Aber das passt schon.. ohne forward declaration funktioniert's.. Danke trotzdem fuer den Hinweis..

    ciao..

  • Hallo an alle..
    Also ich bin jetzt an einem Punkt angelangt, wo ich forward declarations und header incluisions anwenden muss. Zusaetzlich zweifle ich an meiner Kenntnis ueber die Richtige Verwendung von C++ Header-Files.. deshalb: Koennte mir jemand erklaeren, wann ich Headers inkludieren muss und wann es nicht notwendig ist (in Verbindung mit Namespaces).. ein Link (oder Aehnliches) macht's auch (hab danach gegoogelt, aber nichts Brauchbares gefunden :-\).

    Dank im Voraus fuer euere Hilfe..
    ciao..

  • im prinzip sollts immer ein pärchen geben, jedes .cpp hat sein .h mit den prototypen/class deklarationen. im .cpp file includest du das .h, im .h file machst du weitere includes die nötig sind.

    forward declarations brauchst du nur wenn ein name zu einem bestimmten zeitpunkt in einem .h file noch nicht bekannt ist weil er weiter unten erst deklariert wird. mit einer forward deklaration sagst du nur das es den namen mal geben wird, du musst ihn dann trotzdem irgendwie zur verfügung stellen.

    hth :)

  • Zitat von fren

    im prinzip sollts immer ein pärchen geben, jedes .cpp hat sein .h mit den prototypen/class deklarationen. im .cpp file includest du das .h, im .h file machst du weitere includes die nötig sind.

    forward declarations brauchst du nur wenn ein name zu einem bestimmten zeitpunkt in einem .h file noch nicht bekannt ist weil er weiter unten erst deklariert wird. mit einer forward deklaration sagst du nur das es den namen mal geben wird, du musst ihn dann trotzdem irgendwie zur verfügung stellen.

    hth :)

    So weit so gut, also verstehe ich es eh richtig. Nun habe ich das Problem, dass ich versuche, eine Circular Inclusion durch Forward Declarations zu umgehen. Im Konkreten habe ich folgende Abhaengigkeiten:

    Node (benutzt Camera, Light, Model)
    Camera (abgeleitet von Node)
    Light (abgeleitet von Node)
    Model (abgeleitet von Node)

    Dann habe ich folgendes in den Files stehen:
    File: node.h


    File: camera.h


    Und schlieszlich bekomme ich in den Files: camera.cpp, light.cpp, model.cpp an entsprechenden Positionen den Fehler: xxx.cpp(20): error C2027: use of undefined type 'Xxxx' c:\...\node.h(yy) : see declaration of 'Xxxx'. Im naechsten File hab ich die Posititonen markiert.
    File: camera.cpp

    Jemand eine Idee, weshalb er die Definition nicht animmt oder warum der Fehler auftritt?

    Bin fuer jeden Hint dankbar..

    fren Danke fuer die Erklaerung..

    ciao..

  • hm, dumme idee, gib mal den namespace bei den funktionen im cpp explizit an

    du musst auf jedenfall im node.cpp die anderen .h files includen, die forward declaration hilft nur im .h, aber ich nehme an das hast du

    ansonsten fällt mir beim ersten durchschaun kein fehler auf

  • so, ich werd mal versuchen, das zu erklären, hier wurden ein paar sachen vermischt:

    Prinzipiell versucht man, die Abhängigkeiten zwischen verschiedenen Sourcecodemodulen so gering wie möglich zu halten - ganz speziell zwischen Headerdateien. In C++ ist das extrem wichtig, weil ansonsten die Compilezeiten drastisch anwachsen können.
    Um das zu erreichen, gibt es u.a. das Prinzip der (forward) declarations, mit dem eine Name eingebracht wird. Dieser muss, sozusagen bevor er verwendet wird, noch definiert werden (--> definition), d.h., der Typ wird um seine Definition vervollständigt. Um sich das vorstellen zu können, muss man noch folgendes wissen: wenn C++-Code übersetzt wird, läuft dieser zuerst durch den Präprozessor, dann erst durch den Compiler. Der Präprozessor wandelt alle preprocessor directives (z.B. #include ... oder #pragma ... oder #define ...) um und ersetzt sofort alle Verwendungen von Makros (#define) im Code. Den Output des ganzen bezeichnen wir in C++ als translation unit, das ist also ein fertiges Stück Sourcecode ohne Abhängigkeiten zu anderen Dateien (die #include-Anweisungen sind vom Präprozessor durch den Inhalt der entspr. Dateien ersetzt worden!)

    Jetzt bleibt noch die Frage (um die's hier geht), wo man die definition braucht und wo die declaration genügt:
    Prinzipiell kann man in einem Header die definition immer "verstecken" (=weglassen), (unter anderem) wenn man
    - einen Pointer auf den Typ deklariert
    - eine Referenz auf den Typ deklariert

    Der Grund dafür ist logisch: ein Pointer und eine Referenz sind immer gleich groß, ganz egal, welches Objekt sich dahinter verbirgt! D.h., dass der Compiler die Klassenstruktur von A nicht kennen muss, wenn ich z.B. folgendes

    Code
    A *p_a;
    A &r_a;
    A const* pc_a;

    deklariere.

    Das ganze hat auch eine Patternmäßige Ausprägung, wenn bei sehr komplexen Strukturen gezielt versucht wird, die Implementierung zu verstecken und heißt "pimpl idiom" (mix aus "pointer" und "implementation").

    Wo brauche ich jetzt die Definition? Überall, wo ich auf die Klasseninterna zugreife, also z.B., wenn in der zur Header gehörigen CPP-Datei die Methoden definiert werden (auch wieder so was, weil im Header wurden sie ja nur deklariert, für Funktionen gilt also das gleiche!)

    Code
    #include "class_a.h"
    
    
    A::A() {
    }

    oder aber z.B. beim Aufruf von Methoden von A (in x.cpp).

    Zum letzten Fehler: using namespace ... gilt, wie der Name sagt, für die Benutzung von Namespaceelementen, nicht für deren Deklaration! D.h., die Methodendeklarationen entweder als

    Code
    Loader::Camera::Camera() {...}

    oder schöner

    Code
    namespace Loader {
       Camera::Camera() {...}
    }


    Hoffe, die Infos helfen!

    Stefan
    ISO C++ Standardisierung

  • Zitat von slapi

    so, ich werd mal versuchen, das zu erklären, hier wurden ein paar sachen vermischt:
    ...
    Hoffe, die Infos helfen!

    Stefan
    ISO C++ Standardisierung

    1000 Dank (pro Compilerfehler ein "Danke Sehr" ;-)).. Das war's.. Hab nur die Klassen-/Struct- usw. Deklarationen in die Namespaces gepackt aber nicht die Definitionen. Die Forward Declarations habe ich eh so gehabt (also bei Pointer und References Forward Declarations verwenden usw.). Jetzt kann ich wenigstens ruhigen gewissens die Forward Declarations verwenden.. die waren mir, bevor du sie mir erklaert hast, etwas suspekt.. :thumb:

    PS: Danke auch an fren. Du hattest natuerlich auch recht.. ich habe es nur nicht gewuszt.. aber jetzt weisz ich's.

    ciao..

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!