Should one use forward declarations instead of inc

2019-01-03 12:11发布

Whenever a class declaration uses another class only as pointers, does it make sense to use a class forward declaration instead of including the headerfile in order to pre-emptively avoid problems with circular dependencies? so, instead of having:

//file C.h
#include "A.h"
#include "B.h"

class C{
    A* a;
    B b;
    ...
};

do this instead:

//file C.h
#include "B.h"

class A;

class C{
    A* a;
    B b;
    ...
};


//file C.cpp
#include "C.h"
#include "A.h"
...

Is there any reason why not to do this wherever possible?

9条回答
forever°为你锁心
2楼-- · 2019-01-03 12:44

Fun fact, in its C++ styleguide, Google recommands using #include everywhere but to avoid circular dependencies.

查看更多
ら.Afraid
3楼-- · 2019-01-03 12:44

Is there any reason why not to do this wherever possible?

Absolutely: It breaks encapsulation by requiring the user of a class or function to know and duplicate implementation details. If those implementation details change, code that forward declares can be broken while code that relies on the header will continue to work.

Forward declaring a function:

  • requires knowing that it's implemented as a function and not an instance of a static functor object or (gasp!) a macro,

  • requires duplicating the default values for default parameters,

  • requires knowing its actual name and namespace, since it may just be a using declaration that pulls it into another namespace, perhaps under an alias, and

  • may lose out on inline optimization.

If the consuming code relies on the header, then all those implementation details can be changed by the function provider without breaking your code.

Forward declaring a class:

  • requires knowing whether it's a derived class and the base class(es) it's derived from,

  • requires knowing that it's a class and not just a typedef or a particular instantiation of a class template (or knowing that it is a class template and getting all the template parameters and default values correct),

  • requires knowing the true name and namespace of the class, since it may be a using declaration that pulls it into another namespace, perhaps under an alias, and

  • requires knowing the correct attributes (perhaps it has special alignment requirements).

Again, forward declaring breaks the encapsulation of these implementation details, making your code more fragile.

If you need to cut header dependencies to speed up compilation time, then get the provider of the class/function/library to provide a special forward declarations header. The standard library does this with <iosfwd>. This model preserves the encapsulation of implementation details and gives the library maintainer the ability to change those implementation details without breaking your code, all while reducing the load on the compiler.

Another option is to use a pimpl idiom, which hides implementation details even better and speeds up compiles at the cost of a small run-time overhead.

查看更多
老娘就宠你
4楼-- · 2019-01-03 12:45

One case in which you don't want to have forward declarations is when they are themselves tricky. This can happen if some of your classes are templated, like in the following example:

// Forward declarations
template <typename A> class Frobnicator;
template <typename A, typename B, typename C = Frobnicator<A> > class Gibberer;

// Alternative: more clear to the reader; more stable code
#include "Gibberer.h"

// Declare a function that does something with a pointer
int do_stuff(Gibberer<int, float>*);

Forward-declarations are the same as code duplication: if the code tends to change a lot, you have to change it in 2 places or more each time, and that is no good.

查看更多
混吃等死
5楼-- · 2019-01-03 12:45

Is there any reason why not to do this wherever possible?

The only reason I think of is to save some typing.

Without forward declarations you can include header file just once, but I don't advice to do so on any rather big projects due to disadvantages pointed by other people.

查看更多
6楼-- · 2019-01-03 12:50

Yes, using forward declarations is always better.

Some of the advantages they provide are:

  • Reduced compilation time.
  • No namespace pollute.
  • (In some cases)may reduce the size of your generated binaries.
  • Recompilation time can be significantly reduced.
  • Avoiding potential clash of preprocessor names.
  • Implementing PIMPL Idiom thus providing a means of hiding implementation from the interface.

However, Forward declaring a class makes that particular class an Incomplete type and that severely, restricts what operations you can perform on the Incomplete type.
You cannot perform any operations which would need the compiler to know the layout of the class.

With Incomplete type you can:

  • Declare a member to be a pointer or a reference to the incomplete type.
  • Declare functions or methods which accepts/return incomplete types.
  • Define functions or methods which accepts/return pointers/references to the incomplete type (but without using its members).

With Incomplete type you cannot:

  • Use it as a base class.
  • Use it to declare a member.
  • Define functions or methods using this type.
查看更多
太酷不给撩
7楼-- · 2019-01-03 12:52

The forward-declaration method is almost always better. (I can't think of a situation where including a file where you can use a forward declaration is better, but I'm not gonna say it's always better just in case).

There are no downsides to forward-declaring classes, but I can think of some downsides for including headers unnecessarily:

  • longer compilation time, since all translation units including C.h will also include A.h, although they might not need it.

  • possibly including other headers you don't need indirectly

  • polluting the translation unit with symbols you don't need

  • you might need to recompile source files that include that header if it changes (@PeterWood)

查看更多
登录 后发表回答