Forward declaration include, on top of declaration include (ClassFwd.h + Class.h)
Asked Answered
E

4

12

In Effective C++ (3rd edition), Scott Meyers, in Item 31, suggests that classes should have, on top of their classic Declaration (.h) and Definition (.cpp) files, a Forward Declaration Include File (fwd.h), which class that do not need the full definition can use, instead of forward declaring themselves.

I somewhat see the case for it, but I really don't see this as a viable option... It seems very hard to maintain, rather overkill and hardly necessary.

I can, however, see its use for template forward declarations, which are rather heavy. But for simple classes? It seems to be that it's a pain to maintain and will create a whole lot of almost empty include files that serve a very small purpose... is it worth the hassle?

Here's a example:

// Class.h
class Class
{
    Class();
    ~Class();
};

// ClassFwd.h
class Class;

// Class.cpp
Class::Class()
{
}

Class::~Class()
{
}

My question:

What do you guys think? If this a good practice?

NOTE I am mostly interested in the arguments FOR this practice, to see if I missed something that would make me agree with Scott Meyers.

Electroluminescence answered 14/10, 2010 at 16:3 Comment(0)
E
7

I used forward declaration header files for all my libraries. A library would typically have this structure:

lib/
  include/
    class headers + Fwd.h
src/
  source files + internal headers

The lib/include directory would contain all public classes headers along with one forward declarations header. This made the library light-weight on the include side. Any header outside of this library only includes the forward header (Fwd.h), while sources outside of this library includes the necessary complete headers. One can also provide a convenience header (Lib.h) that includes all the other headers, for use in source files.

Another thing to place in the forward declaration header is typedefs for shared_ptr, especially in the case of an inheritance hierarchy with factory classes that return pointers to implementations.

The above is useful for larger applications with lots of internal libraries. A refinement of the above for this case would be to place the public headers in lib/include/lib. This way clients of your library would have to include lib/.... Think of this as a namespace for your headers.

Good luck!

Edi answered 14/10, 2010 at 16:38 Comment(4)
Thanks for the reply, however, you are merely stating what you do, not why you do it. The only argument you provide is for shared_ptr, which I already solved by having a FORWARD_SHARED() macro, which forwards declare a class and its pointer automatically. This is very lightweight and easy to read...Electroluminescence
Ok, the reason is to reduce compile time and to centralize forward declarations. If all forward declarations are in one file it is easy to add new ones when new classes are made. Same with pointer typedefs. Why compile time is reduced should be obvious. Does this make sense to you? Keeping header files clean from anything but forward declarations will help as your codebase grows bigger.Equity
Ah! So you have a single Fwd.h file! Not one per header! Now I see how that can make sense... Alright, will ponder on that for a while...Electroluminescence
Exactly! :-) It worked very well for me when I was a C++ developer.Equity
C
1

Placing a simple class Whatever; in its own header has no advantages and lots of disadvantages.

Especially in the case where accessing a header can be time consuming, one uses simple forward declarations to avoid accessing headers; putting them in their own headers would defeat the purpose...

With templated things, as you note, it's a different matter. E.g. check out <iosfwd> from the standard library.

Cheers & hth.

Consciousness answered 14/10, 2010 at 16:11 Comment(3)
My problem is that I agree with you, but not with Meyers. Might be the answer I am looking for, but I want my opinion to be challenged! :DElectroluminescence
With modern disk caching, the compile time (and memory) hit from accessing a header isn't based so much on the number of headers but the complexity of code inside. Including a much simpler header in place of the full definition doesn't defeat the purpose at all, then.Rollo
@BenVoigt: re "Including a much simpler header in place of the full definition", the question is including a header versus writing just class X;. The former entails at least one extra disk access. There's a reason for build farms.Consciousness
A
1

The practice allows the code user not to think about whether a class is regular or template. The user just #inludes "corresponding_fwd.h" file and has a class reference. One less annoyance for the user is A Good Thing. But if it's a small project or class' creator is the only class' user then it might be more annoyance. So, it depends.

Adinaadine answered 14/10, 2010 at 16:15 Comment(1)
Ok, I see your point. A am still a bit skeptic that it's worthwhile, considering the extra effort. It seems that if I was purely a user, it would be ok, but if I am also a dev, then the time or energy I save including fwd.h without thinking is offset by the time wasted creating them...Electroluminescence
A
0

If you have a large solution this is your only chance to handle the inherent dependencies:

struct A {
    B* m_pB;
};

struct B {
    A* m_pA;
};

Now A and B may reasonably be in different header files, maybe even different projects. Yet, their dependency is not some design defect but entirely logical and necessary. What do you do?

  1. First include a single Types.h forward-declarating header for eeach required project, i.e., the forward declaration does not have its own header file per class.
  2. Then include the Class.h of all required projects. These headers will require forward declarations to compile.
  3. Include the headers of the main project.

In a rather large solution (500k LOC) I've found this pattern to be very easily manageable. Otherwise, if you change a class declaration, where do you find all forward declarations that you may have made individually in any number of other header files?

Armyworm answered 14/10, 2010 at 16:9 Comment(1)
You example seems like a case for forward declaration in general, not for fwd.h files in particular.Electroluminescence

© 2022 - 2024 — McMap. All rights reserved.