The key practice here is having around each foo.h file a guard such as:
#ifndef _FOO_H
#define _FOO_H
...rest of the .h file...
#endif
This prevents multiple-inclusions, with loops and all such attendant horrors. Once you do ensure every include file is thus guarded, the specifics are less important.
I like one guiding principle Adam expresses: make sure that, if a source file just includes a.h
, it won't inevitably get errors due to a.h
assuming other files have been included before it -- e.g. if a.h
requires b.h
to be included before, it can and should just include b.h itself (the guards will make that a noop if b.h was already included previously)
Vice versa, a source file should include the headers from which it is requiring something (macros, declarations, etc), not assume that other headers just come in magically because it has included some.
If you're using classes by value, alas, you need all the gory details of the class in some .h
you include. But for some uses via references or pointers, just a bare class sic;
will suffice. E.g., all other things being equal, if class a can get away with a pointer to an instance of class b (i.e. a member class b *my_bp;
rather than a member class b *my_b;
) the coupling between the include files can be made weaker (reducing much recompilation) -- e.g. b.h
could have little more than class b;
while all the gory details are in b_impl.h
which is included only by the headers that really need it...