tags:

views:

994

answers:

8

This is a rather basic question, but it's one that's bugged me for awhile.

My project has a bunch of .cpp (Implementation) and .hpp (Definition) files.

I find that as I add additional classes and more class inter-dependencies, I have to #include other header files. After a week or two, I end up with #include directives in lots of places. Later, I'll try removing some of the #includes and discover that everything still works because some OTHER included class is also #including what I just removed.

Is there a simple, easy rule for putting in #includes that will stop this ugly mess from happening in the first place? What is the best practice?

For example, I've worked on projects where the Implementation .cpp file ONLY includes the corresponding Definition .hpp file, and nothing else. If there are any other .hpp files that need to be used by the Implementation .cpp, they are all referenced by the Definition .hpp file.

+13  A: 

Some best practices:

  • Every .cpp or .C file includes all headers it needs and does not rely on headers including other related headers
  • Every .hpp or .h file includes all its dependencies and does not rely on the included headers including other related headers
  • Every header is wrapped with:

    #ifndef HEADER_XXX_INCLUDED
    #define HEADER_XXX_INCLUDED
    ...
    #endif /* HEADER_XXX_INCLUDED */
    
  • Headers do not include each others in cycles

  • Often: there is a single "project-wide header file" like "config.h" or ".h" which is always included first by any .cpp or .C file. Typically this has platform related configuration data, project-wide constants and macros etc.

These are not necessarily "best practice", but rules which I usually follow also:

  • Project-specific headers are included as #include "..." and before the system-wide headers, which are included as #include <...>
  • Project-specific headers are included in alphabetical order as a way to ensure that there is no accidental, hidden requirement on which order they are included. As every header should include its dependents and the headers should be protected against multiple inclusion, you should be able to include them in any order you wish.
antti.huima
I also do #endif //HEADER_XXX_INCLUDED so to see what the endif matches up with.
Scott Chamberlain
Interesting. Doesn't this mean that the .cpp file will have the same (possibly more) #includes as it's corresponding .hpp file?
Runcible
I'm confused by your second bullet. IMHO, you should always include the headers your class relies on in the .h file for your class. If every class follows this practice, you should be able to rely on them to include whatever they need. You're advocating including all of their dependencies as well?
rmeador
I like to create unit tests that do nothing but #include one header file. Unintended dependencies are quickly weeded out when the tests are compiled.
Ferruccio
If you're using Visual Studio 2005 or later, and portability is not an issue, you could replace the '#ifndef HEADER_XXX' / '#define HEADER_XXX' / '#endif // HEADER_XXX' lines with a simple '#pragma once' line where your #ifndef line would go.
RobH
You should emphasize that system (and other external library) headers should be included last. This is probably the biggest source of ordinal include dependencies in our code.
Greg Rogers
To save compile time, I typically include big system headers, like windows.h, as the first includes in every .cpp file and don't include them in the headers. If a header depends on the system header, you can do a #ifndef on something the system header defines...
RobH
... and put a #error line inside that block that tells the developer to include that particular system header before including your header. The #error line would be something like: #error You must include windows.h before including foobar.h
RobH
A common "best-practice" is to always include the header that corresponds to a cpp file first in the list of headers. This helps to enforce that all the dependencies of the header are included properly. Might be worth adding.
Dan Olson
I disagree with the .cc/.cpp/.C file including all of its header files and stuff it requires. That is what the corresponding .h file is for. In the Foo.cc I #include "Foo.h", nothing else. Foo.h should contain all of the #includes to make sure that my .cc compiles and can be properly linked against.
X-Istence
X-Istence, if Foo.cc is implementation of class Foo and Foo.h its declaration, there can be headers which you only need to compile the unit Foo.cc but which are not needed for using the class.
antti.huima
+5  A: 

Use only the minimum amount of includes needed. Useless including slows down compiling.

Also, you don't have to include a header if you just need to pointer to a class. In this case you can just use a forward declaration like:

class BogoFactory;

edit: Just to make it clear. When I said minimum amount, I didn't mean building include chains like:

a.h
#include "b.h"

b.h
#include "c.h"

If a.h needs c.h, it needs to be included in a.h of course to prevent maintenance problems.

abababa22
Typically, unless I can get away with just a forward declaration or two, if a file uses something that's defined in a header, I include that header, even if it's already included by one of the headers that I'm already including. That prevents the problem that Joel Coehoorn pointed out.
RobH
Yep, I realized that my post can be interpreted this way, which I of course didn't mean. Edited.
abababa22
The exception to the above is when I'm including system headers. Then I'll include as few of those as I can get away with. (I.e., if system Header A includes system header B, and I'm including system header A, then I won't also include system header B.)
RobH
@RobH: However you can't always rely on that. On certain systems certain system header files will not include things they rely on, and you may need to re-order the headers just to get the whole damn thing to compile! Annoying!
X-Istence
+3  A: 

I always use the principle of least coupling. I only include a file if the current file actually needs it; if I can get away with a forward declaration instead of a full definition, I'll use that instead. My .cpp files always have a pile of #includes at the top.

Bar.h:

class Foo;

class Bar
{
    Foo * m_foo;
};

Bar.cpp:

#include "Foo.h"
#include "Bar.h"
Mark Ransom
I see. So it sounds like you're .h file will typically have very few (if any) #includes.
Runcible
Yes - most often it will be for the standard library containers, e.g. #include <vector>.
Mark Ransom
In one (moderately complicated) code base I've seen a marked improvement in rebuild times using this approach.
dmckee
I actually like this answer best because it's so simple.
Runcible
+2  A: 

Building on what antti.huima said:

Let's say you have classes A, B, and C. A depends on (includes) B, and both A and B depend on C. One day you discover you no longer need to include C in A, because B does it for you, and so you remove that #include statement.

Now what happens if at some point in the future you update B to no longer use C? All of a sudden A is broken for no good reason.

Joel Coehoorn
+3  A: 

There are several problems with the #include model used in C/C++, the main one being that it doesn't express the actual dependency graph. Instead it just concatenates a bunch of definitions in a certain order, often resulting in definitions coming in a different order in each source file.

In general, the include file hierarchy of your software is something you need to know in the same way as you know your datastructures; you have to know which files are included from where. Read your source code, know which files are high up in the hierarchy so you can avoid accidentally adding an include so that it will be included "from everywhere". Think hard when you add a new include: do I really need to include this here? What other files will be drawn in when I do this?

Two conventions (apart from those already mentioned) which can help out:

  • One class == one source file + one header file, consistently named. Class A goes in A.cpp and A.h. Code templates and snippets are good here to reduce the amount of typing needed to declare each class in a separate file.
  • Use the Impl-pattern to avoid exposing internal members in a header file. The impl pattern means putting all internal members in a struct defined in the .cpp file, and just have a private pointer with a forward declaration in the class. This means that the header file will only need to include those headerfiles needed for its public interface, and any definitions needed for its internal members will be kept out of the headerfile.
JesperE
+1  A: 

In A.cpp, always include A.h first, to ensure that A.h has no additional dependencies. Include all local (same module) files before all project files before all system files, again to ensure that nothing depends on pre-included system files. Use forward declarations as much as possible. Use #indef/#define/#endif pattern If a header is included in A.h, you don't need to include it in A.cpp. Any other headers A.cpp needs must be explicitly included, even if they happen to be provided by other .h files.

Arkadiy
+2  A: 

Organizing code files in C and C++:

Comptrol
+2  A: 

Check out John Lakos's Large-Scale C++ Software Design. Here's what I follow (written as an example):

Interface

// foo.h
// 1) standard include guards.  DO NOT prefix with underscores.
#ifndef PROJECT_FOO_H
#define PROJECT_FOO_H

// 2) include all dependencies necessary for compilation
#include <vector>

// 3) prefer forward declaration to #include
class Bar;
class Baz;
#include <iosfwd> // this STL way to forward-declare istream, ostream

class Foo { ... };
#endif

Implementation

// foo.cxx
// 1) precompiled header, if your build environment supports it
#include "stdafx.h"

// 2) always include your own header file first
#include "foo.h"

// 3) include other project-local dependencies
#include "bar.h"
#include "baz.h"

// 4) include third-party dependencies
#include <mysql.h>
#include <dlfcn.h>
#include <boost/lexical_cast.hpp>
#include <iostream>

Precompiled Header

// stdafx.h
// 1) make this easy to disable, for testing
#ifdef USE_PCH

// 2) include all third-party dendencies.  Do not reference any project-local headers.
#include <mysql.h>
#include <dlfcn.h>
#include <boost/lexical_cast.hpp>
#include <iosfwd>
#include <iostream>
#include <vector>
#endif
Tom