Ben Usman
Ben Usman

Reputation: 8387

C++ classes refer to each other ( => error + field '...' has incomplete type)

Classes in my application work like this: Creature has few fields with Actions. When these Actions must be run Creature calls someActionField->do(this). Action has method viod do(Creature* cr) and all information about what to do with this Creature.

So, Creature must have Action field and know that Action has do method. Action must know that Creature has such fields like: Will, HP, etc...

I've got

creature.h

 #include "effect.h"
 #include "heedupdate.h"

 namespace Core
 {

 class Action;

 class Creature : public NeedUpDate
 {
 public:
     virtual ~Creature();
     int HP;
     Action onHit;
     Action onDie;
// ...


 };

 }
#endif

And action.h

#include "creature.h"

namespace Core
{


class Action
{
public:
Action();
virtual void _do(Creature* cr);
virtual ~Action();
};

But in this case field `onDie' has incomplete type error appears. If I include action.h into creature.h - I use files 'before each other'.

Upvotes: 4

Views: 2130

Answers (5)

Mat
Mat

Reputation: 206831

You Creature class has members of type Action. The compiler needs to know the full definition of the Action class to compile that - an incomplete type as produced with a forward declaration is not enough.

The Action class only requires a pointer to a Creature object in that header. In that case, the compiler only needs to know that Creature will be defined at some point.

In your specific case, you could get away with inverting the order in which you declare your classes.

(i.e. forward-declare Creature in action.h, and include action.h in creature.h)

Upvotes: 8

Alok Save
Alok Save

Reputation: 206566

When you forward declare a type, all the compiler know is that this type exists; it knows nothing about its size, members, or methods, hence it is called an Incomplete Type

You cannot use an incomplete type to declare a member(because compile needs to know the size of the type while declaring it) and hence you get the error.

You don't need to #include "creature.h" in action.h but you just need to forward declare class Creature. You do need to #include "action.h" in creature.h

Your header files should have the following construct:

creature.h

#include "effect.h"
#include "action.h"
#include "heedupdate.h"

action.h

class creature;

This makes use of two rules:

  • One can Declare functions or methods which accepts/return incomplete types:

action.h only declares a function which accepts an Incomplete type(Creature)

  • One cannot declare a member to an incomplete type.

creature.hhas to include action.h because it declares a member of type Action.

Upvotes: 3

BЈовић
BЈовић

Reputation: 64253

Use references, or pointers :

     #include "effect.h"
     #include "heedupdate.h"

     namespace Core
     {

     class Action;

     class Creature : public NeedUpDate
     {
     public:
         virtual ~Creature();
         int HP;
         Action & onHit;
         Action & onDie;
    // ...


     };

     }

#endif

This way you can break dependencies and not need a fully declared Action class

Upvotes: 0

David Hammen
David Hammen

Reputation: 33126

You don't need to #include "creature.h" in action.h. All you need is a forward declaration of class Creature. You do need to #include "action.h" in creature.h because onHit and onDie are instances of Action.

Upvotes: 2

Karoly Horvath
Karoly Horvath

Reputation: 96266

in action.h put class Creature; and in the other one #include "action.h"

For pointers you don't need complete definition because it's just a pointer and the compiler can generate "code" for it. If you use a simple class/struct the compiler has to have knowledge of the type because it needs to know how big it is.

Upvotes: 3

Related Questions