Jump to content
  • Advertisement
Sign in to follow this  
gcooper

C++ header inclusion question

This topic is 1514 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So, consider the following code:

#ifndef HEADER1
#define HEADER1

#include "header2.h"

#endif

Keep in mind that header 2 also has header guards, and all my other headers in the project. However, when I compile the above code, I get an error saying that namespaces/classes that EXIST in header2 don't actually exist.

 

But then I tried an old trick:

#ifndef HEADER1
#define HEADER1

namespace namespace_in_header2{
	class class_i_need;
}

#endif

And after that I only included the actual header2.h in my header1.cpp. And it worked!

 

I'm sure that the first problem is caused somehow, by including header 2 again and again until chaos happens. But why? I mean all my header have header guards! Also, why including header2.h only in the cpp file fixes things? Wouldn't there still be a way in which it still gets added 2 or more times?

 

 

Share this post


Link to post
Share on other sites
Advertisement

But why?

chances are that Header2 includes Header1 again. Maybe not directly, but by including something that includes something that..

if you're using visual studio, then there is a compile flag to show the includes, that way you might track down the recursion.

But then I tried an old trick:...
And after that I only included the actual header2.h in my header1.cpp. And it worked!

That's actually not a trick, that's the way you should preferably do it. Don't include stuff that you don't need, it might massively reduce your compile time once your project grows.
A lot of projects have build time issues and trying to solve it later on can be quite complicated. Just like you now might not know how the double-include happened, later on you might not know what path something should actually be include as everything includes everything. You might even run into issues where you cannot create a propper include order without cleaning it up (or creating really really bad hacks).

as a simple example, check your compile time if you include <windows.h> in some file, it's not affecting your program, just being processed. now imagin that for every single file (because at some point you will have such a big monster that might include other 'monsters' like directx/opengl, sound libs, network libs).

Share this post


Link to post
Share on other sites

Some basic guidelines that can get you through most inclusion issues:

  1. Only include what you need.
  2. Only include headers in source files, never in other headers
  3. Use #pragma once.

Sometimes you'll need to deviate from these rules, but in the rare occasion that you do, you'll know.

 

Short of putting all headers in one huge header file, how can #2 be accomplished?  Not trying to be a wiseguy - I'm not well-versed in C++ and would honestly like to know.

Share this post


Link to post
Share on other sites

I think #2 should actually read: "Only include headers in headers if you can't get away with forward declarations"

 

Hence the "Sometimes you'll need to deviate from these rules, but in the rare occasion that you do, you'll know."  It's very rare that you can't get away with forward declarations.

 

 


Short of putting all headers in one huge header file, how can #2 be accomplished?  Not trying to be a wiseguy - I'm not well-versed in C++ and would honestly like to know.

 

As madhed mentioned above, forward declarations.  If header 2 contains a "Foo" class that you need to reference in header 1, just declare class foo; at the top of header 1.  If cpp file 1 includes header 1 AND header 2, the linker will take care of it.

Edited by SeraphLance

Share this post


Link to post
Share on other sites

 

I think #2 should actually read: "Only include headers in headers if you can't get away with forward declarations"

 

Hence the "Sometimes you'll need to deviate from these rules, but in the rare occasion that you do, you'll know."  It's very rare that you can't get away with forward declarations.

 

 


Short of putting all headers in one huge header file, how can #2 be accomplished?  Not trying to be a wiseguy - I'm not well-versed in C++ and would honestly like to know.

 

As madhed mentioned above, forward declarations.  If header 2 contains a "Foo" class that you need to reference in header 1, just declare class foo; at the top of header 1.  If cpp file 1 includes header 1 AND header 2, the linker will take care of it.

 

 

Its quite common to #include headers in header files.  Manual creation of forward declarations is gonna lead to lots of subtle errors as you now have your dependencies spread across many files.  Just use #pragma once at the top of every header file, include it where needed, and you won't have issues.  As far as #pragma once being non-portable, I know of no remotely modern C++ compiler that doesn't support it (http://en.wikipedia.org/wiki/Pragma_once#Portability).

Share this post


Link to post
Share on other sites


Hence the "Sometimes you'll need to deviate from these rules, but in the rare occasion that you do, you'll know." It's very rare that you can't get away with forward declarations.

 

Unless you are using/writing templated classes. It's c++ after all, so templates are a (good) thing. Anything else though, should really be forward declared.

 


Its quite common to #include headers in header files.

 

Its also quite common to use i.e. the Singleton anti-pattern, that doesn't make it a good thing.

 


Manual creation of forward declarations is gonna lead to lots of subtle errors as you now have your dependencies spread across many files.

 

Care to elaborate how this is a bad thing? I never ever had an error directly related to forward declaration, and having depencies spread is really a good thing - now if I have to include "X.h" into "Y.h" I can be asured that Y only has the barely minimum depencies that X relies on in its declaration, mostly due to templates/typedefs. Instead of having Y.h now suddenly contain every single include that might be there in the include-chain, which gives you nothing but increased compile times. Even with #pragma once, having all header-files included in other header-files will still lead to recompilation of half your project if you make a change to the header of certain classes.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!