pragma once Problem?



  • Ich habe in einem kleinen Projekt das Problem, dass VS die Definitionen (structs, klassen ...) nicht mehr Ordnungsgemäß kennt wenn ich die header mehrmals eingebunden habe.

    Die Header inkludieren sich gegenseitig, was normalerweise in einer endlosen Aktion enden würde, deshalb benutze ich "pragma once" um das zu vermeiden.

    Es ist für mich aber wichtig dass die eine header z. B. die typedefs/structs/classes der anderen header kennt und andersrum.

    Hier ein kleines Beispielszenario:

    // finc.h
    
    #pragma once
    
    #include "sinc.h"
    
    struct FINCSTRUCT {
    	SINCSTRUCT *s;
    };
    
    // sinc.h
    
    #pragma once
    
    #include "finc.h"
    
    struct SINCSTRUCT {
    	FINCSTRUCT *f;  // <-- hierauf bezieht sich später die Fehlerausgabe
    };
    
    // main.cpp
    
    #include <windows.h>
    #include "finc.h"
    
    int main(void)
    {
    	FINCSTRUCT f;
    	return 0;
    }
    

    Visual Studio 2005 Ausgabe:

    Error 1 error C2143: syntax error : missing ';' before '*' c:\test\src\sinc.h 7
    Error 2 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int c:\test\src\sinc.h 7
    Error 3 error C4430: missing type specifier - int assumed. Note: C++ does not support default-int c:\test\src\sinc.h 7

    Hat jemand eine Lösung dafür?



  • Wenigstens einmal musst du eine Vorwärtsdeklaration machen:

    // sinc.h
    
    // Pragmas sind Compiler-abhängig, das hier funktioniert immer
    #ifndef SINC_H
    #define SINC_H
    
    struct FINCSTRUCT;
    
    struct SINCSTRUCT {
        FINCSTRUCT *f;
    };
    
    #endif
    
    // finc.h
    #ifndef FINC_H
    #define FINC_H
    
    #include "sinc.h"
    
    struct FINCSTRUCT {
        SINCSTRUCT *s;
    };
    #endif
    


  • Danke, das funktioniert 🙂



  • Nur bei mir leider nicht 😞

    BusUeberwachung.h

    #include <windows.h>
    #include "Framegrabber.h"
    
    #ifndef _BusUeberwachung_h_
    #define _BusUeberwachung_h_
    
    class BusUeberwachung
    {
    public:
    	BusUeberwachung();
    	~BusUeberwachung();
    
    	void meldeBusAnforderung(int _prioritaet, Framegrabber* _refFramegrabber);
    };
    #endif
    

    Framegrabber.h

    #include "BusUeberwachung.h"
    
    #ifndef _Framegrabber_h_
    #define _Framegrabber_h_
    
    class Framegrabber
    {
    public:
    	Framegrabber(BusUeberwachung* _refBusUeberwachung);
    	~Framegrabber();
    };
    #endif
    

    BusUeberwachung.cpp

    #include "BusUeberwachung.h"
    
    BusUeberwachung::BusUeberwachung()
    {
    }
    
    BusUeberwachung::~BusUeberwachung()
    {
    }
    
    void BusUeberwachung::meldeBusAnforderung(int _prioritaet, Framegrabber* _refFramegrabber)
    {
    }
    

    Framegrabber.cpp

    #include "Framegrabber.h"
    
    Framegrabber::Framegrabber(BusUeberwachung* _refBusUeberwachung)
    {
    	this->refBusUeberwachung = _refBusUeberwachung;
    }
    
    Framegrabber::~Framegrabber()
    {
    }
    

    Ich schätze mal, dass es daran liegt, dass ich in den cpp-Dateien auch noch mal die Header einbinde. Hab die Include-Wächter jetzt schon in verschiedensten Kombinationen eingesetzt, aber es will nicht klappen:

    ...\busueberwachung.h(2) : warning C4182: #include nesting level is 361 deep; possible infinite recursion



  • Wie gesagt, die Include-Guards bewirken, daß die Header jeweils einfach eingebunden werden (genau wie #pragma once, aber portabel). Um die Elemente gegenseitig bekannt zu machen, benötigst du Forward-Deklarationen:

    #ifndef _BusUeberwachung_h_
    #define _BusUeberwachung_h_
    
    #include <windows.h>
    //#include "Framegrabber.h"
    class Framegrabber;
    
    class BusUeberwachung
    {
    public:
        BusUeberwachung();
        ~BusUeberwachung();
    
        void meldeBusAnforderung(int _prioritaet, Framegrabber* _refFramegrabber);
    };
    #endif
    

    (das "#include "Framegrabber.h"" kannst du dann an den Anfang der zugehörigen CPP-Datei setzen)

    PS: Damit der Guard etwas bringt, sollte er den gesamten Header einschließen - inklusive der beteiligten #include's.



  • Aber mit den Forward-Deklarationen kennt der Compiler die Implementationen nicht mehr:

    ...\testsuite\test.cpp(25) : error C2514: 'Framegrabber' : class has no constructors
        ...\visionsystem\busueberwachung.h(6) : see declaration of 'Framegrabber'
    ...\testsuite\test.cpp(36) : warning C4150: deletion of pointer to incomplete type 'Framegrabber'; no destructor called
        ...\visionsystem\busueberwachung.h(6) : see declaration of 'Framegrabber'
    


  • Okay, funktioniert doch. Irgendwie ...



  • Für deine Klassendeklaration (sprich: im Header) reicht die Forward-Deklaration vollkommen aus. Für die Implementation (im CPP-File) benötigst du dann die komplette Definition der Klasse.


Anmelden zum Antworten