3

When working with a library, whether it be my own or external, there are lot of classes with forward declarations. The same classes also have includes as well depending on the situation. When I use a certain class, I need to know whether certain objects that the class uses, are forward declared or are they #include(d). The reason is I want to know whether I should be including both headers or just one.

Now I know it is fairly simple to check, just compile (or go through all the headers until you find the object in question either #include(d) or forward declared). But with large projects, a simple compile takes a long time, and going into each include file to check whether the class in question is being included or forward declared is tedious, especially if it is a few levels deep. To illustrate the problem further:

Class A is a Class B is a Class C which has a pointer to Class Foo

I include Class A and want to know whether Class Foo is ready for use right away, or whether I have to do the following:

#include "ClassA.h"
#include "ClassFoo.h"

So, is there a quick and easy way to find out about this dependency without compiling or going into the depended headers? (one of the reasons I ask this question is because I want to eventually make an add-in for VS and/or stand-alone program for this if the functionality does not already exist)

Thanks!

Samaursa
  • 16,527
  • 21
  • 89
  • 160

3 Answers3

7

In a source file you should not depend on what the other header files include.

You should explicitly include every type that your code depends on.
If you do not use a type (ie just passing a pointer or a reference around) then you don't need its definition so don't include its header file (The header file for the methods you are using should have at least a forwward declaration).

So in your particular instance it is hard to tell.
Is you source file explicitly uses any members from Foo then you need to include "ClassFoo.h" otherwise don't. There is no need to go digging around in header files (they may change anyway). Just check exactly what your source file uses and include those (and only those) header files.

In the header file: Prefer forward declaration to inclusion. This way you limit/break circular dependencies.

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Right, and this risks multiple passes over some header files, so it follows that include guards are *de rigueur*. – dmckee --- ex-moderator kitten Aug 09 '10 at 18:44
  • @dmckee: If the question asked about thouse I would have answered about that as well but not strictly relevant to the question. Also should note that modern compilers build pre-compiled headers and this limit the actuall number of passes. – Martin York Aug 09 '10 at 18:48
  • In Havok, I have hkpWorld (now this is a simple example, and I already know to include the other 'includes' but this kind of thing happens all the time) which forward declares hkpRigidBody. I need to create a world and add a rigid body so I need both included. In this case I have to open up the header of each and make sure I am not including one or the other twice. If I understand correctly, what you are saying is that even if hkpWorld includes hkpRigidBody explicitly in its header, I should still include hkpRigidBody in my .cpp file? Won't that increase compile time? – Samaursa Aug 09 '10 at 19:48
  • @Samaursa: No you don't need to look in the header files. Each header file should contain header guards (as mentioned above by dmckee (so maybe it was more relevant than I first though (sorry dmckee)). The header guards stop multiple inclusion. Yes compile time theoretically will be increased but in practice is not; this is because of pre-compiled headers. If you use an object (access a member (method or variable (including constructor/destructor))) you should include its header file in the source file (do not depend on other header files to implicitly include information for you). – Martin York Aug 10 '10 at 00:00
  • Ah, ok that clears it up. I was under the impression that even with header guards the header is read again by the compiler just because of the additional #include. The confusion began with this article. I am not sure what the cost is for opening and closing files, but I think in my project it should not be a big source of worry. http://www.cygnus-software.com/papers/precompiledheaders.html I tried this with a new project, and although the header is being opened up every time it is included, it is not recompiled and does not go past the line #pragma once or an #ifndef block – Samaursa Aug 10 '10 at 02:36
  • @Samaursa: You mean the link to the document that is over 10 years old. But yes pre-compiled headers are now widely supported and do improve compile time performance. – Martin York Aug 10 '10 at 03:58
  • Even though it is 10 years old, is mostly still correct and is one of the few tutorials on precompiled headers that I could find. The part of the article that caused the confusion was the #pragma message statements that would print out a message if the file is opened and read. I put the #pragma message above the guards which would cause it to be printed multiple times. – Samaursa Aug 10 '10 at 17:14
1

Actually I am finding eliminating as many header includes as is humanly possible actually helps hella more. See this answer. By cutting out more #include statements, its much more clear exactly what is part of the source file (#includes are a blackbox - you never know what is getting linked in by that one line of text). If a class Foo needs the implementation details of a class Bar, then Foo.h should not include "Bar.h", but rather, contain only a forward declaration. Foo.cpp should include Bar.h.

Foo.h

class Bar ; // fwd declare wherever possible

class Foo
{
  // I can haz needs Bar
  void do( Bar *bar ) ;
} ;

Foo.cpp

#include "Foo.h"
#include "Bar.h" // I can has needs complete implementation details.

Foo::do( Bar *bar )
{
}

Bar.h

class Bar
{
  // code..
} ;
Community
  • 1
  • 1
bobobobo
  • 64,917
  • 62
  • 258
  • 363
0

If you're using class A then you should only care about the private interface of the base class C (and possibly additional interface in A. If the class is designed properly, you won't need to access Foo directly because it will be encapsulated in C's interface and not exposed to the public world. In this case you won't need an include to Foo at all because it's not part of C's public interface. If in fact Foo is part of the interface to C in some way, then I argue that C.h should include Foo.h as well, so that clients can use it without having to make the determinations you're asking about.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • Well, sometimes that is not always possible. For example in Havok when you include hkpRigidBody, even though it knows about the world, you have to include the world explicitly because it has been forward declared. Same for hkpWorld (which has all these rigid bodies). That is forward declared as well, even though you pass in hkpRigidBody* to the world directly through a function. So in those situations I have to go through each header to make sure I am not including some class twice (that is, it has not been forward delcared), which will increase compile time. – Samaursa Aug 09 '10 at 19:44