I'm late answering this, but there's not one reasonable answer to date, despite being a popular question with highly upvoted answers....
As illustrated by the Standard library's <iosfwd>
header, the proper way to provide forward declarations for others is to have a forward declaration header. For example:
a.fwd.h:
#pragma once
class A;
a.h:
#pragma once
#include "a.fwd.h"
#include "b.fwd.h"
class A
{
public:
void f(B*);
};
b.fwd.h:
#pragma once
class B;
b.h:
#pragma once
#include "b.fwd.h"
#include "a.fwd.h"
class B
{
public:
void f(A*);
};
The maintainers of the A
and B
libraries should each be responsible for keeping their forward declaration headers in sync with their headers and implementation files, so - for example - if the maintainer of "B" comes along and rewrites the code to be...
b.fwd.h:
template <typename T> class Basic_B;
typedef Basic_B<char> B;
b.h:
template <typename T>
class Basic_B
{
...class definition...
};
typedef Basic_B<char> B;
...then recompilation of the code for "A" will be triggered by the changes to the included b.fwd.h
and should complete cleanly.
Say - instead of using a forward declaration header as explained above - code in a.h
or a.cc
instead forward-declares class B;
itself:
a.h
or a.cc
did include b.h
later:
B
(i.e. the above change to B broke A and any other clients abusing forward declarations, instead of working transparently).b.h
- possible if A just stores/passes around Bs by pointer and/or reference)
#include
analysis and changed file timestamps won't rebuild A
(and its further-dependent code) after the change to B, causing errors at link time or run time. If B is distributed as a runtime loaded DLL, code in "A" may fail to find the differently-mangled symbols at runtime, which may or may not be handled well enough to trigger orderly shutdown or acceptably reduced functionality.If A's code has template specialisations / "traits" for the old B
, they won't take effect.