Pointers, References and Values by Michael D. Crawford Continued...

Avoiding Unnecessary Header File Inclusion

Avoid unnecessary build dependencies and long compile times
by not including a header file when a forward reference would suffice.

One property of the C++ compiler is that if it does not need to know the size of an object, or the calling conventions of any of its member functions when it encounters the name of a class or struct, then one does not need to have previously included the declaration for the class or struct. You can just say "class classname;" before mentioning it in a prototype, and C++ will know that classname is a class that will get defined before it is actually used. This creates an incomplete type in the symbol table of the compiler.

This is known as a forward declaration of a class or struct. Function prototypes and extern variable declarations are more familiar examples of forward declarations.

For example, instead of this in Bar.h:

#include "Foo.h"

class Bar{
   public:
      Bar( const Foo &inFoo );

   private:
      long   mMemberVariable;
};

you can do this to avoid the dependency on and compile time of Foo.h:

class Foo;

class Bar{
   public:
      Bar( const Foo &inFoo );

   private:
      long   mMemberVariable;
};

You only need to include Foo.h when you actually depend on the definition of Foo - when you need to know its size, when you allocate or delete one, or call one of its member functions or refer to one of its member variables. The proper place to #include "Foo.h" is in the class implementation (Bar.cpp) file:

#include "Bar.h"
#include "Foo.h"

Bar::Bar( const Foo &inFoo )
	: mMemberVariable( inFoo.MemberFunction() )   // requires we have seen Foo
	                                              // class declaration
{

}

Note that the very first header file in Bar.cpp is the class Bar's class declaration file Bar.h. This is a good practice. I feel that it is important for a header file to stand on its own - to not require the inclusion of other header files before it, and to allow multiple header files to be included in other places in any order.

One way to help ensure this is to include a Class.h header as the very first header in a Class.cpp implementation file. This is probably the one place that you can count on the header being able to be included before any others, and when you write the implementation you have usually just written, or just started to write the header so it is a good time to make sure the header file will compile on its own.

(Thanks to Haim Zamir of Live Picture for pointing this out to me - Haim is one of the best programmers I have ever met.)

The header file should include any other header files that are absolutely required to get it to compile cleanly and no more. Do not include extra headers as a convenience to users.

Also you almost always want to declare only one class in each header. The only case where you might want to declare two classes in one header file is where it absolutely does not make sense for one to be used without the other being fully declared also - but consider future users who might come up with ways to use your code in ways you did not imagine when you first wrote your code.

Using the class or struct keywords to forward declare a class or structure allows you to avoid unnecessary inclusion of header files. It is not just that that cuts down on compile times (which may be considerable for large projects), it also makes real dependencies clear. Where depencies exist, you want to move them into the implementation when you can and not into the interface.

An important goal in making code maintainable is reducing dependencies. You do need to have some dependencies (after all, objects of different classes must communicate somehow), but you do not want any dependencies that are unnecessary. Also, to make your code reusable, you need to allow a class to be used in a new application without dragging in all the code from the old application. Managing your classes' dependencies makes this possible.

For this reason, the first approximation of my recommendation of how to choose parameters and member variables in a class declaration is:

Use pointers and references, rather than passing by value or storing members as whole objects.

This is only a first approximation though, what you really want to do gets a little more complex than that.

next button previous page contents all programming tips titles

Copyright © 2000, 2001, 2002, 2005 Michael D. Crawford. All Rights Reserved.

One Must Not Trifle With Wizards For It Makes Us Soggy And Hard To Light