Consider I have a Class A and a Class B and their corresponding header:
a.h
#ifndef CLASS_A
#define CLASS_A
/* forward declare A */
class A;
/* includes */
#include "b.h"
/* define class A */
class A {
public:
A() : p_b(nullptr) {}
B *p_b;
};
#endif
b.h
#ifndef CLASS_B
#define CLASS_B
/* forward declare B */
class B;
/* includes */
#include "a.h"
/* define class B */
class B {
public:
B() : m_a() {}
A m_a;
};
#endif
This does not work:
To compile the implementation of A into an object-file, I first include a.h, that forward declares A and then includes b.h that then declares and defines B. But when B is defined it does not know the size of A and therefore can not declare an object of A as a member of B.
A however does not need to know the size of B, as it only has a pointer to B and could be completely defined before B get's defined. Therefore the size of B can be completely known before it gets used as a member and the complete declaration SHOULD be fine.
Common sense though tells that the a.c file should always look like this:
#include "a.h"
[...]
Can I actually solve the problem by including b.h before a.h in a.c ? Would this be against some holy convention of having the first line of an implementation file being the include of it's header?
You are using forward declarations in a backwards manner. The code should look more like this instead:
a.h
#ifndef CLASS_A
#define CLASS_A
/* forward declare B */
class B;
/* define class A */
class A {
public:
A() : p_b(nullptr) {}
B *p_b;
};
#endif
b.h
#ifndef CLASS_B
#define CLASS_B
#include "a.h"
/* define class B */
class B {
public:
B() : m_a() {}
A m_a;
};
#endif
a.h
doesn't need to know what B
actually is, since A
contains a B*
pointer and not a B
object. So a.h
should not be using #include "b.h"
at all, it should be forward declaring B
instead.
b.h
does need to know what A
actually is, since B
contains an A
object and not an A*
pointer. So b.h
should be using #include "a.h"
, which already forward declares B
before defining A
, then b.h
finishes defining B
.
a.c
can then use #include "a.h"
to bring in the declaration of A
so it can finish defining the implementation, and it can use #include "b.h"
only if A
's methods need to access members of B
.