Question

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;
     }
}
Was it helpful?

Solution 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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top