It's well known that using forward declarations is preferable to using #includes in header files, but what's the best way to manage forward declarations?
For a while, I was manually adding to each header file the forward declarations that were needed by that header file. However, I ended up with a bunch of header files repeating the same half-dozen or so forward declarations, which seems redundant, and maintaining these repeated lists got to be a bit tedious.
Forward declarations of typedefs (e.g., struct SensorRecordId; typedef std::vector<SensorRecordId> SensorRecordIdList;
) is also a bit much to duplicate across multiple header files.
So then I made a ProjectForwards.h
file that contains all of my forward declarations and included that wherever it was needed. At first, this seemed like a good idea - much less redundancy, and much easier maintenance of typedefs. But now, as a result of using ProjectForwards.h
so heavily, whenever I add a new class to it, I have to rebuild the world, which slows development.
So what's the best way to manage forward declarations? Should I bite the bullet and repeat individual forward declarations across multiple subsystems? Continue with the ProjectForwards.h
approach? Try to split ProjectForwards.h
into several SubsystemForwards.h
files? Some other solution I'm overlooking?
In computer programming, a forward declaration is a declaration of an identifier (denoting an entity such as a type, a variable, a constant, or a function) for which the programmer has not yet given a complete definition.
Generally you would include forward declarations in a header file and then include that header file in the same way that iostream is included.
The Google style guide recommends against using forward declarations, and for good reasons: If someone forward declares something from namespace std, then your code exhibits undefined behavior (but will likely work).
Forward declarations in C++ are useful to save in compile time as the compiler does not need to check for translation units in the included header. Also it has other benefits such as preventing namespace pollution, allowing to use PImpl idiom and it may even reduce the binary size in some cases.
It sounds like these classes are fairly common to much of your project. You might try some of these:
Do your best to break apart ProjectForwards.h
into several files as you suggested. Make sure each subsystem only gets the declarations it truly needs. If nothing else, that process will force you to think about the coupling between your subsystems and you might find ways to reduce it. These are all good steps toward avoiding over-compilation.
Mimic <iosfwd>
. Have each common class or module provide its own forward-include header that just provides the class names and any convenience typedefs. Then you can #include that everywhere. Yes, you'll repeat the list a lot, but think about it this way: nobody complains about #including <vector>
, <string>
, and <map>
in six different places in their code.
Use Pimpl more often. This will have a similar effect to my previous suggestion but will require more work on your part. If your interfaces are stable, then you can safely provide the typedefs in those headers and #include them directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With