This compiles
#include "Sprite.h"
class GameObject
{
public:
int x, y, w, h;
Sprite sprite;
public:
GameObject();
GameObject(int _x, int _y, int _w, int _h);
virtual ~GameObject();
};
This doesn't
class Sprite;
class GameObject
{
public:
int x, y, w, h;
Sprite sprite;
public:
GameObject();
GameObject(int _x, int _y, int _w, int _h);
virtual ~GameObject();
};
I know that I could forward declare and use pointer for Sprite but why doesn't forward declaration works here.
Doesn't "class Sprite;" tells that Sprite exists?
I'm trying #include as much classes in .cpp and avoid it in .h at any cost.
Also classes are not including each other so there is no need to use Sprite*.
I guess my understanding of what forward declaring is is wrong or something because I don't see a reason why this doesn't work.
Thanks in advance.
Pretend you're the compiler. Without having a complete declaration of Sprite
at your disposal, how is it possible to determine whether the Sprite
is only one byte big, or one hundred thousand bytes big?
You don't need to know much about the class when you only need a pointer to the class (or a reference to a class, or a few other minor things); but when you need to actually use the class, a mere forward declaration is not sufficient. It's not always enough to know that "Sprite
exists"; sometimes it's necessary to know how big it is, too. And without a complete declaration, that's not possible.
Forward declarations only work with references or pointers, if the type appears in the depending class declaration.
class Sprite;
class GameObject
{
public:
int x, y, w, h;
Sprite* sprite; // <<<<
// or Sprite& sprite;
public:
GameObject();
GameObject(int _x, int _y, int _w, int _h);
virtual ~GameObject();
};
Care to include the Sprite.h
file in your implementation, and initialize the member in your constructor implementation ideally (a reference would require that strictly).
Sprite
can't be incomplete type here, because the size and layout of it must be known as the non-static member of class GameObject
.
(Note the 3rd one)
Any of the following contexts requires class T
to be complete:
definition or function call to a function with return type T or argument type T;
definition of an object of type T;
declaration of a non-static class data member of type T;
new-expression for an object of type T or an array whose element type is T;
lvalue-to-rvalue conversion applied to a glvalue of type T;
an implicit or explicit conversion to type T;
a standard conversion, dynamic_cast, or static_cast to type T* or T&, except when converting from the null pointer constant or from a pointer to void;
class member access operator applied to an expression of type T;
typeid, sizeof, or alignof operator applied to type T;
arithmetic operator applied to a pointer to T;
definition of a class with base class T;
assignment to an lvalue of type T;
a catch-clause for an exception of type T, T&, or T*.
On the other hand, if you declare it as pointer or reference, incomplete type is fine and forward declaration will be allowed.