Preface
The Google Style Guide includes a list of disadvantages of forward declaration
Forward declarations can hide a dependency, allowing user code to skip necessary recompilation when headers change.
A forward declaration may be broken by subsequent changes to the library. Forward declarations of functions and templates can prevent the header owners from making otherwise-compatible changes to their APIs, such as widening a parameter type, adding a template parameter with a default value, or migrating to a new namespace.
Forward declaring symbols from namespace std:: yields undefined behavior.
It can be difficult to determine whether a forward declaration or a full #include is needed. Replacing an #include with a forward declaration can silently change the meaning of code:
Code:
// b.h:
struct B {};
struct D : B {};
// good_user.cc:
#include "b.h"
void f(B*);
void f(void*);
void test(D* x) { f(x); } // calls f(B*)
If the #include was replaced with forward decls for B and D, test() would call f(void*).
Forward declaring multiple symbols from a header can be more verbose than simply #includeing the header.
Structuring code to enable forward declarations (e.g. using pointer members instead of object members) can make the code slower and more complex.
Question
I am particulary interested in the first point, as I cannot come up with a single scenario, where a forward decleration would skip necessary recompilation when headers change. Can anybody tell me how this can happen? Or is this something intrinsic to the google code base?
As this is the first point on the list it also seems rather important.
I think this is a bit unclear too, and perhaps could be worded a little more clearly.
What could it mean for a dependency to be hidden?
Let’s say your file
main.ccneedsheader.hin order to be built correctly.If
main.ccincludesheader.h, then this is a direct dependency.If
main.ccincludeslib.h, and thenlib.hincludesheader.h, then this is an indirect dependency.If
main.ccsomehow depends onlib.hbut does not generate a build error iflib.his not included, then I might call this a hidden dependency.I don’t think the word hidden is a commonplace term for this, however, so I agree that the wording could be refined or expanded.
How does this happen?
I have
main.c,lib.h, andtypes.h.Here is
main.c:Here is
lib.h:Here is
types.h:Now,
main.ccdepends ontypes.hin order to generate the correct code. However,main.cconly has a direct dependency onlib.h, it has a hidden dependency ontypes.h. If I use forward declarations inlib.h, then this breaksmain.cc. And yetmain.ccstill compiles!And the reason that
main.ccbreaks is because it does not includetypes.h, even thoughmain.ccdepends on the declarations intypes.h. Forward declarations make this possible.