# Why not forward-declare everything? (c++)

This topic is 4867 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I've found that it's useful to forward declare the types I'm using in my class header files (or at least the ones that aren't allocated on the stack ). This means that I can just put the include in the CPP file and will allow for a quicker compile Also, clients of the class that don't depend on the forward-declared type are not forced to include it. I do this a lot... and lately I've been thinking I should have a file for each package that forward declares everything in said package Is this a good or bad idea?

##### Share on other sites
Just to ensure we're on the same page... you're talking about doing:
class foo;class bar {    foo * baz;};

#include <foo.h>class bar {    foo * baz;};

?

There's pros and cons to both.

For the first, you have:
Pro: Faster compiles, dosn't lead to cyclilic dependancies
Con: Dosn't include the class body in case you want to call them from an inline function, or have said class a member (as in, not a pointer).
Possibly Pro or Con, depending on opinion: Bugs won't be marked in the header if you rename foo to pie - they'll only appear in code directly using that class (e.g. class implementation).

For the second, you have:
Pro: can include multiple types, allows one to specify the class as a member, and otherwise freely use the type(s).
Con: Increases compile time.

Personally, I prefer the later unless I'm:

1) Breaking a cyclilic dependancy
2) Intentionally hiding the definition (for when I have classes like so:)

class foo {    class implementation; //forward decleration!!!    boost::shared_ptr< implementation > impl;public:    //...public methods...};

That way, if implementation has to deal with voodoo magic (unpleasant namespace/definespace pollution) or is OS-specific (e.g. the network lib I last used this pattern in has an implementation of "implementation" for winsock (for windows, obviously) and another for BSD sockets (for linux)) it dosn't end up screwing over the using code.

If something's taking too long to compile, I break it up and find out which bits are taking so long (e.g. large boost::spirit grammars) and toss them into a source file where they belong. Since I use automatic dependancy-based building, this means I only take the hit when I need to recompile that file.

##### Share on other sites
Thanks for the response.

Quote:
 Original post by MaulingMonkeyJust to ensure we're on the same page... you're talking about doing:class foo;class bar { foo * baz;};Instead of:#include class bar { foo * baz;};?

Yes, except more along the lines of this:

foo.h
#include <math.h>class foo{    vector* vec;    matrix3* matrix;};

math.h
class vector;class matrix3;class matrix4;class quaternion;class vector2;// etc..

Quote:
 There's pros and cons to both.For the first, you have:Pro: Faster compiles, dosn't lead to cyclilic dependanciesCon: Dosn't include the class body in case you want to call them from an inline function, or have said class a member (as in, not a pointer).

I'm not too worried about this. I can always inline functions later in development, when I need the speed. Plus, if the function ever changes I don't have to re-compile, just re-link.

Quote:
 Possibly Pro or Con, depending on opinion: Bugs won't be marked in the header if you rename foo to pie - they'll only appear in code directly using that class (e.g. class implementation).

I don't really consider this a big deal. If I forward declare always, whenever it is possible, then these errors become pretty obvious after the first few.

Quote:
 For the second, you have:Pro: can include multiple types, allows one to specify the class as a member, and otherwise freely use the type(s).Con: Increases compile time.

When you say include multiple types, do you mean through just a single header? Yeah that is a valid argument.

I think I'm going to try using a common header that forward-declares everything and see how it goes.
Another con that comes to mind is that adding a new class to this file will result in a full recompile. But I'm assuming I won't be adding new classes very often..

##### Share on other sites
I use forward declarations all the time. The time savings in compilation far outweigh any of the cons listed above. They don't really even bother me that much...

There is an annoyance of sometimes being forced to change it to an include if I want to inline a function like he mentioned but it's just a judgment call whether to inline it or keep it in the source file.

For me it's a little more work than just including everything in the header but it just feels more correct.

##### Share on other sites
Having only declarations in headers force you to use pointers instead of value types. This may (Bridge pattern) or may not (dynamic allocations everywhere) be desirable. You've got to judge on a case by case basis.

##### Share on other sites
Be aware that you will also not be able to use most smart pointers to hold forward declared classes as class members. (If you do, your destructor will not be called, but rather a compiler default-constructed one will.) This can be a hard memory leak to find, as well, because it is so easy to think such great things about smart pointers. Fortunately boost::shared_ptr will probably give you at least a warning. std::auto_ptr probably won't, though.

David

##### Share on other sites
(your destructor for the forward declared class, that is)

##### Share on other sites
Quote:
 Original post by Anonymous PosterBe aware that you will also not be able to use most smart pointers to hold forward declared classes as class members. (If you do, your destructor will not be called, but rather a compiler default-constructed one will.) This can be a hard memory leak to find, as well, because it is so easy to think such great things about smart pointers. Fortunately boost::shared_ptr will probably give you at least a warning. std::auto_ptr probably won't, though.David

Eh, are you sure about that?

I've got a forward declared class held in a smart pointer in my app, and the destructor is most definitely being called. Is this another case of Visual Studio 2002 deviating from the standard then?

Actually, from checking the boost::shared_ptr documentation, it says that the type doesn't have to be a complete type when you declare a shared_ptr, surely this wouldn't be the case if something as dangerous as the destructor not being called was happening?

##### Share on other sites
and for a great example of this you don't need to look longer than the C++ Standard Library and the header "iosfwd" :D

##### Share on other sites
Oh, I thought you meant like this:

// Doing forward declarationvoid foo;int main() {  foo();}void foo() {}// vs. not doing forward declarationvoid foo() {}int main() {  foo;}

In *that* case I definitely prefer to avoid the forward declarations as much as possible, because it's extra typing you have to maintain. Within the one source file, you should only put them where they're needed due to cyclic dependency - because it then serves as documentation of said dependency.

1. 1
2. 2
3. 3
Rutin
22
4. 4
5. 5

• 13
• 19
• 14
• 9
• 9
• ### Forum Statistics

• Total Topics
632931
• Total Posts
3009292
• ### Who's Online (See full list)

There are no registered users currently online

×