Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: .h Files and forward Declarations  (Read 24503 times)

0 Members and 1 Guest are viewing this topic.

Saboba42

  • Newbie
  • *
  • Posts: 8
    • View Profile
.h Files and forward Declarations
« on: February 18, 2011, 03:35:50 pm »
I have been running into an issue while coding in C++ in the Code::Blocks compiler.  I declare a class in a header file and then put that header file in another header file, but the second header file compiles as if the first class had not been declared.  Codeblocks still acts like it knows about the second header (auto-completing in the second header with things from the first header and such).

In coding terms:

Header 1:
<header guard>

namespace GQE
{
    class A
    {
          public int z;
    };
};

Header 2:

<header guard>

#include "Header1.h"

namespace GQE
{
     Class B
     {
          void Foo(A* theA);
     };
};

Compiler error: in B::void Foo(A* theA): A has not been declared


The problem is fixed when I do this (-> marks the addition):

<header guard>

#include "Header1.h"

namespace GQE
{

->     Class A;

     Class B
     {
          void Foo(A* theA);
     };
};

However, this does not work:

Header_types.h:

<header guard>
namespace GQE
{
     class A;
};

Header 2:

<header guard>

#include "Header_types.h"

namespace GQE
{
     Class B
     {
          void Foo(A* theA);
     };
};

This, however, will compile:

Header 2:

<header guard>

namespace GQE
{
   Class A;
};

namespace GQE
{
     Class B
     {
          void Foo(A* theA);
     };
};

Isn't this exactly equivalent to the above example that doesn't work???  To make this even more crazy, I am building this project from the Basic Game Engine source from the wiki, and the problem is only happening in a few files I have added to the project - the rest of the project does the exact same thing as above, except it works.

The same thing happens for enums and it's driving me crazy.  Help appreciated!  If you need more information, I'll see what I can do.  The headers are both added to the same project, and are in the same file in that project, so I know that isn't the issue.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
.h Files and forward Declarations
« Reply #1 on: February 18, 2011, 03:44:53 pm »
Make sure that you didn't define the same header guards in two different files -- happens easily with copy and paste ;)
Laurent Gomila - SFML developer

devlin

  • Full Member
  • ***
  • Posts: 128
    • View Profile
.h Files and forward Declarations
« Reply #2 on: February 18, 2011, 07:13:28 pm »
I take it "#pragma once" doesn't work in Code::Blocks? :)

Saboba42

  • Newbie
  • *
  • Posts: 8
    • View Profile
.h Files and forward Declarations
« Reply #3 on: February 18, 2011, 09:35:52 pm »
@Laurent:
Nope, header-guards are unique

@devlin:
I don't think it does, I tried using #pragma once in addition to my guards, which didn't solve the problem, and using only #pragma once resulted in multiple includes.  Perhaps I am using it wrong - I hadn't heard of it before and only looked it up on wiki.

For the record, my header guards are of the type:

#ifndef EVENTMANAGER_H_INCLUDED
#define EVENTMANAGER_H_INCLUDED

//The code here

#endif

JAssange

  • Full Member
  • ***
  • Posts: 104
    • View Profile
.h Files and forward Declarations
« Reply #4 on: February 18, 2011, 10:11:32 pm »
GCC (and therefore code blocks) should support #pragma once fine.

Saboba42

  • Newbie
  • *
  • Posts: 8
    • View Profile
.h Files and forward Declarations
« Reply #5 on: February 19, 2011, 08:05:36 pm »
@JAssange:

Mind giving a little demonstration of how to use the #prima once command correctly?  Like I said, the way I tried it didn't make anything better.

JAssange

  • Full Member
  • ***
  • Posts: 104
    • View Profile
.h Files and forward Declarations
« Reply #6 on: February 19, 2011, 08:19:04 pm »
Quote from: "Saboba42"
@JAssange:

Mind giving a little demonstration of how to use the #prima once command correctly?  Like I said, the way I tried it didn't make anything better.

You put #pragma once at the very top of the header file and don't include any header guards, the compiler will insure it is not included multiple times.

DoctorJ

  • Newbie
  • *
  • Posts: 21
    • View Profile
.h Files and forward Declarations
« Reply #7 on: February 20, 2011, 04:18:19 am »
I tried this:
for file: "header1.h"
Code: [Select]
#ifndef HEADER1_H_INCLUDED
#define HEADER1_H_INCLUDED

namespace GQE
{
class A
{
public: int z;
};
};

#endif // HEADER1_HPP_INCLUDED

and for file "header2.h"
Code: [Select]
#ifndef HEADER2_H_INCLUDED
#define HEADER2_H_INCLUDED

#include "header1.h"

namespace GQE
{
class B
{
void Foo(A* theA);
};
};

#endif // HEADER2_HPP_INCLUDED

and I included (but do not use) these files within a simple main program. It compiles ok.

A couple of caveats... include files for cpp are often named with the "hpp" extension instead of "h" - buts thats no biggie.

Per the GCC documentation - avoid pragma commands I don't see "pragma once" in the documentation and it hasn't worked when I've tried it in the past.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
.h Files and forward Declarations
« Reply #8 on: February 20, 2011, 10:16:10 am »
#pragma once should always be used in addition to header guards. It is just an extra optimization, not a replacement.
Laurent Gomila - SFML developer

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
.h Files and forward Declarations
« Reply #9 on: February 20, 2011, 01:29:36 pm »
When you limit your project to a compiler that supports #pragma once, where is the point in adding include guards?

#pragma once works fine alone, it's just not very portable (though g++ and MSVC support it).
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

DoctorJ

  • Newbie
  • *
  • Posts: 21
    • View Profile
.h Files and forward Declarations
« Reply #10 on: February 20, 2011, 03:29:57 pm »
Sorry, I did find "pragma once" in the gcc documentation; along with a warning that it is not always implemented.

Quote
Another way to prevent a header file from being included more than once is with the `#pragma once' directive. If `#pragma once' is seen when scanning a header file, that file will never be read again, no matter what.

`#pragma once' does not have the problems that `#import' does, but it is not recognized by all preprocessors, so you cannot rely on it in a portable program.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
.h Files and forward Declarations
« Reply #11 on: February 20, 2011, 05:43:57 pm »
Quote
When you limit your project to a compiler that supports #pragma once, where is the point in adding include guards?

You're right. I always think in terms of portability, but sometimes you just don't care.
Laurent Gomila - SFML developer

Saboba42

  • Newbie
  • *
  • Posts: 8
    • View Profile
.h Files and forward Declarations
« Reply #12 on: February 20, 2011, 06:15:07 pm »
Ok, so I am gathering that #pragma once is out as a solution.

To further deepen the mystery, this is also giving me problems:

.H file for my event manager:

Code: [Select]
#ifndef EVENTMANAGER_H_INCLUDED
#define EVENTMANAGER_H_INCLUDED

#include "GQE/GQE_Types.h"
#include "GQE/App.h"

namespace GQE
{
    class EventManager
    {
        public:

        /**
        *  Init Functions
        */
        EventManager();
        ~EventManager();

        /**
        *  Allows access to the App and its members
        */
        void RegisterApp(App* theApp);

        /**
        *  Receives passed game events and caries out appropriate actions
        */
        void MakeHappen(const MakeEvent theEvent, double x, double y, int nPlayerNum);


        private:
    ///=====================================================================///
    ///VARIABLES:
        App* mApp;
    };//class EventManager
};//namespace GQE

#endif // EVENTMANAGER_H_INCLUDED


-----------------------------------------------------------------------------------

The relevant parts of "GQE/GQE_Types.h" are:

Code: [Select]
#ifndef   GQE_TYPES_HPP_INCLUDED
#define   GQE_TYPES_HPP_INCLUDED

#include <map>
#include <string>

// The following defines help with OS/Compiler specific calls
#ifdef WIN32
#ifndef MINGW
#define STRICMP _stricmp
#else
#define STRICMP strcasecmp
#endif
#else
#define STRICMP strcasecmp
#endif

namespace GQE
{

  /// Status Enumeration for Status Return values < A functioning enum
  enum StatusType {
    // Values from -99 to 99 are common Error and Good status responses
    StatusAppMissingAsset = -4, ///< Application failed due to missing asset file
    StatusAppStackEmpty   = -3,  ///< Application States stack is empty
    StatusAppInitFailed   = -2,  ///< Application initialization failed
    StatusError           = -1,  ///< General error status response
    StatusAppOK           =  0,  ///< Application quit without error
    StatusNoError         =  0,  ///< General no error status response
    StatusFalse           =  0,  ///< False status response
    StatusTrue            =  1,  ///< True status response
    StatusOK              =  1   ///< OK status response

    // Values from +-100 to +-199 are reserved for File status responses
  };

///More enums that actually work here

   ///Lists all possible Events < I added this enum to the file and it does not work
  enum MakeEvent
  {
    AddSpam = 0,
    LastMakeEvent
  };
};//namespace GQE

------------------------------------------------------------------------------

And Code::Blocks yells back at me:

||=== Debug ===|
C:GQE\GQE\EventManager.h|34|error: ISO C++ forbids declaration of 'MakeEvent' with no type|
C:\GQE\GQE\EventManager.h|34|error: expected ',' or '...' before 'theEvent'|
||=== Build finished: 2 errors, 0 warnings ===|

devlin

  • Full Member
  • ***
  • Posts: 128
    • View Profile
.h Files and forward Declarations
« Reply #13 on: February 20, 2011, 07:17:12 pm »
Quote from: "Saboba42"
Ok, so I am gathering that #pragma once is out as a solution.

... because?

I'm only using pragma once (without include guards - I haven't used them for several years after getting bit by the same-name "feature" once) and compiling projects happily on windows, linux and mac os x.

DoctorJ

  • Newbie
  • *
  • Posts: 21
    • View Profile
.h Files and forward Declarations
« Reply #14 on: February 20, 2011, 09:29:08 pm »
Sabo, I tried out those code snippets as files (had to add #endif to the end of the GQe_Types.h code above.) I don't know what you are using for App.h so I made a test file:
Code: [Select]
#ifndef APP_H_INCLUDED
#define APP_H_INCLUDED

class App
{
    public:
    sf::RenderWindow thisApp;
};


#endif // APP_H_INCLUDED

and within my main program (which #include's these three headers) I have the lines:
Code: [Select]
  App myApp;
   myApp.thisApp.Create(sf::VideoMode(400, 200, 32), "Test Program");

It compiles and runs without a hiccup. I'm guessing that your problem is more subtle than header guards.