11

I ran into a situation where my build speeds have started to become large and have affected productivity. I had already minimized header dependencies before using forward declarations. Now I've turned to forward declarations to further reduce these dependencies as a method of trying to reduce compile times.

I understand the concept of forward declarations, but I didn't quite understand how much you could forward declare until I came across this. As I understand it, I can forward declare all method/function parameter and return types for function declarations.

I have a lot of situations where I have (assume I have include guards in header):

//myclass.h
#include "someclass.h"
#include "someotherclass.h"

class MyClass{
public:
    SomeOtherClass foo(SomeClass y);
};

With forward declarations, I can now do something like:

//myclass.h
class SomeClass;
class SomeOtherClass;

class MyClass{
public:
    SomeOtherClass foo(SomeClass y);
};
//include actual header files in myclass.cpp

I believe this will require the header to be included at the call site some how, but removes the include from the header. And the caller doesn't use that call, I would assume It would just be a net gain of needing that dependency at all on the call site.

I haven't seen this pattern before (only with class members and private function types), so I'm wondering if there is any downside to doing this. Is there a reason why I shouldn't just forward declare all of these types?

Krupip
  • 1,340

1 Answers1

15

Yes, at least one reason exists.

The Google Style Guide acknowledges that forward declarations can improve compile time, but still advises developers to prefer #include declarations when possible (especially when using third-party libraries), and lists some reasons why:

  • 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.
  • 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.

There are, of course, dissenting opinions elsewhere on the Web. Most reasonable[citation needed] treatments of the subject admit there are benefits and drawbacks to either approach, and so, as usual, it's a judgment call whether to use or not use this tool in any given situation.


These are not the only articles written on the subject, nor are they authoritative. They're just two relevant pages I happened to stumble across (one of them being a response to the other); there is of course a much wider debate to be found, if you care to look.

This answer was written primarily by just copying information from other sites. The search terms I plugged into Google were:

"c++" "do not use forward declarations"

This got me a decent list of sites on page 1 that could be skimmed to pick out what the conventional wisdom might indicate are the pros and cons of this language feature.

You can try these and other terms and search query formats to find controversy over the use of lots of other optional language tools, too; my personal favorite currently happens to be generics (if they're in Go 2, I will continue using Go 1 as long as it's still supported, and then probably find a different favorite language).