BrownBeard93423
BrownBeard93423

Reputation: 179

Field Has Incomplete Type, Compiling From Multiple Files

I am trying to compile several files together for an agent based simulation of a zombie apocalypse (Awesome, right!?) Anyway, I am getting an error that I think has to do with the order in which header files are being included, but I can't wrap my head around how to figure out what's going wrong and how to fix it. The exact error is: "In file included from main.cpp, field 'Location' has incomplete type." Then similarly, "In constructor Creature::Creature() 'Location' undeclared".

Here are my files:

definitions.h

#ifndef definitions_h
#define definitions_h
class Creature;
class Item;
class Coords;

class Grid
{

public:
      Creature*** cboard;
      Item*** iboard;

      Grid(int WIDTH, int HEIGHT);
      void FillGrid(int H, int Z); //initializes grid object with humans and zombies  
      void Refresh(); //calls Creature::Die(),Move(),Attack(),Breed() on every square
      void UpdateBuffer(char** buffer);
      bool isEmpty(int startx, int starty, int dir);

};

class Random
{
    public:
        int* rptr;
        void Print();
        Random(int MIN, int MAX, int LEN);
        ~Random();
    private:
        bool alreadyused(int checkthis, int len, int* rptr);
        bool isClean();
        int len;
};

class Creature
{

public:
      bool alive;
      Coords Location;
      char displayletter;

      Creature() {Location.x=0; Location.y=0;} //ERROR HERE
      Creature(int i, int j) {Location.xvalue(i); Location.yvalue(j);} 

      virtual void Attack();
      virtual void Breed();
      virtual void Move(Creature*** cboard);
      virtual void Die();

      virtual void MoveTo(Creature*** cboard, int dir); 
      virtual int DecideSquare(Creature*** cboard); 
};

class Human : public Creature 
{
public:      
      bool armed; //if armed, chances of winning fight increased for next fight 
      bool vaccinated; //if vaccinated, no chance of getting infected

      int bitecount; //if a human is bitten, bite count is set to a random number
      int breedcount; //if a human goes x steps without combat, will breed if next to a human
      int starvecount; //if a human does not eat in x steps, will die 

      void Attack(Creature*** cboard);
      void Breed(Creature*** cboard); //will breed after x steps and next to human
      void Move(Creature*** cboard); //moves and checks itemboard for food
      void Die(); //depends on bitecount, starvecount, and bool alive

      void MoveTo(Creature*** cboard, int dir);
      int DecideSquare(Creature*** cboard) {Creature::DecideSquare(Creature*** cboard);}

};

class Zombie : public Creature
{
   public:
      Zombie(int i, int j) {Creature::Creature()};
      void Attack(Creature*** cboard); //will attack any adjacent human
      void Breed() {} //does nothing
      void Move(Creature*** cboard) {Creature::Move(Creature*** cboard;}
      void Die(); //can only die from being attacked, never starves


};

class Item
{

};

class Coords
{
  public:   
      int x;
      int y;
      int MaxX;
      int MaxY;

      Coords() {x=0; y=0; MaxX=0; MaxY=0;}
      Coords(int X, int Y, int WIDTH, int HEIGHT) {x=X; y=Y; MaxX=WIDTH; MaxY=HEIGHT; }

      void MoveRight();
      void MoveLeft();
      void MoveUp();
      void MoveDown();
      void MoveUpRight();
      void MoveUpLeft();
      void MoveDownRight();
      void MoveDownLeft();
      void MoveDir(int dir);
      void setx(int X) {x=X;}
      void sety(int Y) {y=Y;}
};

#endif

main.cpp

#include <cstdlib>
#include <iostream>
#include "definitions.h"

using namespace std;

int main(int argc, char *argv[])
{
    system("PAUSE");
    return EXIT_SUCCESS;
}

definitions.cpp

#include <cstdlib>
#include "definitions.h"

Grid::Grid(int WIDTH, int HEIGHT)
{
     //builds 2d array of creature pointers
     cboard = new Creature**[WIDTH];
     for(int i=0; i<WIDTH; i++)
     {
             cboard[i] = new Creature*[HEIGHT];
     }

     //builds 2d array of item pointers
     iboard = new Item**[WIDTH];
     for (int i=0; i<WIDTH; i++)
     {
              iboard[i] = new Item*[HEIGHT];
     }
}

void Grid::FillGrid()
{
     /* For each creature pointer in grid, randomly selects whether to initalize
     as zombie, human, or empty square. This methodology can be changed to initialize
     different creature types with different probabilities */

     int random;

     for (int i=0; i<WIDTH; i++)
     {
         for (int j=0; j<HEIGHT; j++)
         {
             Random X(1,100,1); //create a single random integer from [1,100] at X.rptr
             random=X->rptr;
             if (random < 20)
                cboard[i][j] = new Human(i,j);
             else if (random < 40) 
                  cboard[i][j] = new Zombie(i,j); 
             else 
                  cboard[i][j] = NULL;
         }
     } //at this point every creature pointer should be pointing to either
     //a zombie, human, or NULL with varying probabilities 

}

void Grid::UpdateBuffer(char** buffer)
{
     for (int i=0; i<WIDTH; i++)
     {
         for (int j=0; j<HEIGHT; j++)
         {
             if (cboard[i][j])
                buffer[i][j]=cboard[i][j]->displayletter;
             else
                 buffer[i][j]=' ';
         }
     }

}

bool Grid::isEmpty(int startx, int starty, int dir)
{
     Coords StartLocation(startx,starty,WIDTH,HEIGHT);
     switch(dir)
     {
                case 1:
                     StartLocation.MoveUp();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 2:
                     StartLocation.MoveUpRight();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 3:
                     StartLocation.MoveRight();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 4:
                     StartLocation.MoveDownRight();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 5:
                     StartLocation.MoveDown();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 6:
                     StartLocation.MoveDownLeft();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 7:
                     StartLocation.MoveLeft();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0;
                case 8:
                     StartLocation.MoveUpLeft();
                      if (cboard[StartLocation.x][StartLocation.y])
                        return 0; 
     }
     return 1;
}


void Coords::MoveRight() {(x==MaxX)? (x=0):(x++);}
void Coords::MoveLeft() {(x==0)? (x=MaxX):(x--);}
void Coords::MoveUp() {(y==0)? (y=MaxY):(y--);}
void Coords::MoveDown() {(y==MaxY)? (y=0):(y++);} 
void Coords::MoveUpRight() {MoveUp(); MoveRight();}
void Coords::MoveUpLeft() {MoveUp(); MoveLeft();}
void Coords::MoveDownRight() {MoveDown(); MoveRight();}
void Coords::MoveDownLeft() {MoveDown(); MoveLeft();}
void Coords::MoveDir(int dir)
{
     switch(dir)
     {
                case 1:
                     MoveUp();
                     break;
                case 2:
                     MoveUpRight();
                     break;
                case 3:
                     MoveRight();
                     break;
                case 4:
                     MoveDownRight();
                     break;
                case 5:
                     MoveDown();
                     break;
                case 6:
                     MoveDownLeft();
                     break;
                case 7:
                     MoveLeft();
                     break;
                case 8:
                     MoveUpLeft();
                     break;
                case 0:
                     break;
     }
}

Upvotes: 0

Views: 1919

Answers (2)

Pedro Lamar&#227;o
Pedro Lamar&#227;o

Reputation: 531

Your forward declaration of class Coords in definitions.h is not enough to declare a variable of type Coords.

The forward declaration introduces the type but leaves it incomplete. You can declare a variable with pointer to incomplete type, but not a variable with incomplete type. So you must move the definition of class Coords before the definition of class Creature.

If you find yourself with a circular declaration dependency, you must introduce a pointer or reference declarator to solve it.

Upvotes: 2

When a variable is declared, its type must be known. In your case, this means the definition of Coords must precede its use in the declaration Coords Location;.

Look at it from the compiler's perspective: it needs to know how much space Location will take, and for this it needs to know the definition of Coords. And of course, it's parsing from top to bottom.

Upvotes: 1

Related Questions