I'm trying to separate the following two classes so each class can be defined in its own Header:
#include <iostream>
class Boo;
class Foo
{
public:
Foo(Boo *booPtr)
:booPtr(booPtr){};
virtual ~Foo(){};
Boo *booPtr;
};
class Boo
{
public:
Boo()
:foo(this){};
virtual ~Boo(){};
Foo foo;
int num = 32;
};
int main()
{
Boo *boo = new Boo;
std::cout << "booPtr : " << boo->foo.booPtr->num << '\n';
delete boo;
}
booPtr : 32
Program ended with exit code: 0
And here is my failed attempt at separation:
"Foo.hpp"
#ifndef Foo_hpp
#define Foo_hpp
#include <stdio.h>
#include "Boo.hpp"
class Foo
{
public:
Foo(Boo *booPtr)
:booPtr(booPtr){};
virtual ~Foo(){};
Boo *booPtr;
};
#endif /* Foo_hpp */
"Boo.hpp"
#ifndef Boo_hpp
#define Boo_hpp
#include <stdio.h>
#include "Foo.hpp"
class Boo
{
public:
Boo()
:foo(this){};
virtual ~Boo(){};
Foo foo; // Error : Field has incomplete type 'Boo'
int num = 32;
};
#endif /* Boo_hpp */
"main.cpp"
#include <iostream>
#include "Foo.hpp"
#include "Boo.hpp"
int main()
{
Boo *boo = new Boo;
std::cout << "booPtr : " << boo->foo.booPtr->num << '\n';
delete boo;
}
But I can't build the code since it generate's the following error:
Boo.hpp -> Foo foo; -> "Field has incomplete type 'Boo'"
How can I fix my code?
You have one file that includes the other and vice versa. This creates a cycle of inclusion.
Realize that the #include
macro does nothing but to replace itself (that is, it's line) with the other file. This makes it obvious why you can't have file A include file B.
The obvious solution is to put a forward declaration of Boo in Foo:
#ifndef Foo_hpp
#define Foo_hpp
#include <stdio.h>
class Boo;
class Foo
{
public:
...
Strangely, you already did this before you separated them.
Now a little bit more theory for you: A class is technically a data storage. It needs to know it's size in order to reserve memory. Therefore, it needs to know all the sizes of it's members, which it can only know when they are declared. Therefore, a class needs to include the declaring headers of each class it has as a member. However, a pointer to an object is different (same goes for references). A pointer always takes the same size, that is 32 or 64 bit, depending on your platform (probably 64 bit since we have 64 bit platforms nowadays). Therefore, the class does not need to know the class it points at, the memory it reserves for it's pointer member is always of the same size. That's why a forward declaration, that says nothing about a classes size, is fine here.