Question about #includes

I was wondering if there is a standard convention to where to have all the #includes? I keep putting all my #includes in my .h files which I think they are really supposed to be in the source files. For some reason when I have a class and I put all of its #includes in the .cpp file it doesn't compile. Anyone got any good examples on where to properly place the #includes for the classes and driver program?
A class generally comes in two parts:

1) The definition (class body -- in a .h file)
2) The implementation (function bodies -- in a .cpp file)

The implementation compiles in its own cpp file, but the .h file can be #included in any other cpp file that needs to use the class. So if you have code in a.cpp that uses MyClass, you need to #include "myclass.h" in a.cpp

headers can include other headers. Some people say not to do this, but as long as you guard against multiple includes, there's nothing wrong with it.

The model I follow goes a little something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
////////////////////////////////////////
//  An example header file -- "example.h"

#ifndef __EXAMPLE_H_INCLUDED__  // guard against multiple/recursive includes
#define __EXAMPLE_H_INCLUDED__

//-----------------------------------------
//  here, #include other files that contain classes that must be fully defined in order
//    for this class to work

#include "parentclass.h"
#include <vector>

//-----------------------------------------
//  here, forward declare classes that this class uses -- but that don't need to be
//    fully defined

class AClass;

//-----------------------------------------
//  now, make the actual class

class Example : public ParentClass
{
public:
  void SomeFunctions();

protected:
  std::vector<AClass*>   avector;
};

#endif  // to close the #ifndef 
There's no convention, but here's my advice. It doesn't matter much where you include standard headers and library headers, but for your app's internal headers, follow this system to help prevent infinite inclusion errors: if a header defines a type, it may be included by both headers and source files, but if a header only defines functions, it may only be included by source files. Whenever possible, avoid including in headers. If a class declared in a header requires another class, then you have no other choice, obviously, but other than that it's possible to always include in source files.

EDIT:
Some people say not to do this, but as long as you guard against multiple includes, there's nothing wrong with it.
Inclusion guards don't protect against infinite inclusion.
Last edited on
May I ask what infinite inclusion is? I'm unfamiliar with that term, and have never experienced any trouble with guarded includes.
a.cpp:
#include "b.cpp"

b.cpp:
#include "a.cpp"

That's a very simplified example. In a real world scenario, you'll find that the inclusion is actually several inclusion levels below where the error appears, and the compiler produces a completely different error. Usually an undeclared identifier error.

Here's a more likely example:
(Pretend each file has inclusion guards.)

a.h:
1
2
3
4
5
6
7
#include "functions.h"

struct A{
	int a;
	A();
	int function_A(int i);
};


a.cpp:
1
2
3
4
5
6
7
#include "a.h"

A::A(int i):a(i){}

int A::function_A(){
	return function_f();
}


functions.h:
1
2
3
#include "b.h"

int function_f();


functions.cpp:
1
2
3
4
5
6
#include "functions.h"

int function_f(){
	B a;
	return a.a.a;
}


b.h:
1
2
3
4
5
6
#include "a.h"

struct B{
	A a;
	B();
};


b.cpp:
1
2
3
#include "b.h"

B::B():a(14){}


The place where the error will occur depends on the order of compilation. Let's suppose the compiler starts preprocessing with a.cpp:
After preprocessing:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "a.h" //<- can't include due to inclusion guard
//b.h begins

struct B{
	A a;
	B();
};
//b.h ends
//functions.h begins

int function_f();
//functions.h ends
//a.h begins

struct A{
	int a;
	A();
	int function_A(int i);
};
//a.h ends

A::A(int i):a(i){}

int A::function_A(){
	return function_f();
}

In this example, the error would look something like "Line 5: A: undeclared identifier."
Last edited on
I guess. You're right that guards alone do not protect against that.

However, this doesn't illustrate the dangers of #including in a header file -- it illustrates the dangers of #including .cpp files (and just overall bad design).

There are also unnecessary #includes there (functions.h doesn't need b.cpp -- eliminate that and you eliminate the problem). If you need to #include x.cpp to enhance inlining capabilities (is there another reason to do it? And does that even do anything to begin with?) -- then guard x.cpp, #include it in x.h, and don't include it anywhere else (#include x.h when you need it). The only way I can see that being a problem is if you have a circular reference (A needs B defined and B needs A defined), which is impossible to resolve no matter what you do (bad design is bad design no matter how you set up your includes)
Last edited on
it illustrates the dangers of #including .cpp files (and just overall bad design).
That was a mistake. You read the post before I had a chance to fix it.

functions.h doesn't need b.[h] -- eliminate that and you eliminate the problem
Well, yeah. That's what I said in my first post.

The only way I can see that being a problem is if you have a circular reference (A needs B defined and B needs A defined), which is impossible to resolve no matter what you do (bad design is bad design no matter how you set up your includes)
Actually, something like this happened to me twice during a project. The first time, I managed to fix it by changing the inclusion policy. The second time, well... all I can say is, generic pointers and casting FTW! It's actually easier to produce than you think.
In my case:
Menu depended on ButtonLayer, because it contains buttons (duh)
ButtonLayer depended on Menu, because some instances need to call a menu when a key is pressed. It could be argued that it could have been avoided by having ButtonLayer::getUserInput() return a code when that happens, but the problem is that the caller was a ScriptInterpreter, and I didn't want to give it more responsibilities (it already had enough).
Well, yeah. That's what I said in my first post.


I think we're in agreement about this, we're just saying it differently.

Nothing wrong with including what you need in a header, but don't include what you don't need. Forward declare what you can.

Actually, something like this happened to me twice during a project. The first time, I managed to fix it by changing the inclusion policy [snip] It's actually easier to produce than you think.


I can't fathom any situation where this would come up in practice. Or at least -- any sitation that couldnt've have been prevented with a more thought-out design. I've written many programs and have never seen it happen once.

Being careless with your #includes is indeed cause for trouble. But the general practice of "include what you need, forward declare when you can, and be super careful when including source files" is pretty much fullproof.

The second time, well... all I can say is, generic pointers and casting FTW!


Ew. Ew ew ew. I guess that might be a reasonable solution if you're coming from C... but ewwwwww.

In honesty, though, I don't see how generic pointers would help in this situation anyway. I mean in order to cast to the specific type you'd need to have the type [forward] declared anyway, so what good does the generic pointer do?

Menu depended on ButtonLayer, because it contains buttons (duh)
ButtonLayer depended on Menu, because some instances need to call a menu when a key is pressed. It could be argued that it could have been avoided by having ButtonLayer::getUserInput() return a code when that happens, but the problem is that the caller was a ScriptInterpreter, and I didn't want to give it more responsibilities (it already had enough).


My format above would've worked fine for this. Forward declare the classes -- or include them if the full definition is needed. I have plenty of 2-way (and even N-way) referals to classes in my code and never had any of this trouble. Only trouble comes from the impossible-to-solve circular definition requirement.

I think I'll write an article on this tomorrow for the articles forum. This is actually an interesting topic for me.
Ew. Ew ew ew. I guess that might be a reasonable solution if you're coming from C... but ewwwwww.
Hahaha. Yes, I didn't like it, either, but it was either that or making drastic changes to the design and spend even more time debugging (I didn't know about forward declaration at the time), so I figured "well, a pointer is a pointer".
In honesty, though, I don't see how generic pointers would help in this situation anyway. I mean in order to cast to the specific type you'd need to have the type [forward] declared anyway, so what good does the generic pointer do?
Suppose we have classes A and B which depend on each other. One of them will be using a generic pointer:
a.h:
1
2
3
4
struct A{
	void *generic;
	A(void *p);
};


a.cpp:
1
2
3
4
5
6
7
#include "b.h"

A::A(void *p){
	B *p2=(B *)p;
	//pretend we actually did something with p2
	this->generic=p;
}

Last edited on
forward declarations ftw.

EDIT - Er yeah -- just saw that bit about not knowing about forward declarations at the time. That would complicate things. Heh.


Side note: working on the article now. Fun stuff ^^
Last edited on
I was thinking that perhaps it would be best to include only forward declarations in headers, but I'm not sure if the compiler will like that.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//a.h:
#include "b.h"
struct A;
//a.cpp
#include "a.h"
struct A{
	B *a;
};
//b.h
#include "a.h"
struct B;
//b.cpp
#include "b.h"
struct A{
	A *a;
};

It looks like there's still infinite inclusion. However...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//preprocessed a.cpp:
//a.h begin
	//b.h begin
		//a.h begin
		//a.h end (truncated by inclusion guard)
		struct B;
	//b.h end
	struct A;
//a.h end
struct A{
	B *a;
};

//(cleaned)
struct B;
struct A;
struct A{
	B *a;
};
I'm nearly done with my article. It goes over why the approach I mentioned is benefitial, and how to overcome all possible inclusion problems. Just one more section to write on templates. I'm interested to hear what you'll think of it =D

I'm having a lot of fun writing it. I feel like such a nerd.
Cool I look forward to seeing the article too!
Topic archived. No new replies allowed.