-1

I'm having a problem with #including files in C++. When I try to compile the following code

#ifndef TILE_H_INCLUDED
#define TILE_H_INCLUDED
#include "location.h"
#include "Thing.h"
#include "Container.h"
#include <string>
using namespace std;

class Tile              //VIRTUAL CLASS
{
protected:
    Container onTile;   //holds objects that are on the tile
    Location * loc;     //location
    Tile* N;            //links to Tiles of that direction (null if nothing)
    Tile* E;
    Tile* S;
    Tile* W;
public:
//no constructor because superclass?
//loc can't move
//actions
bool placeOnTile(Thing * i){return onTile.addItem(i);}
    //put a thing on the tile (on the floor)
Thing* takeFrmTile(int i){return onTile.movItem(i);}
    //take a thing from the tile (from the floor)
Thing* access(int i) {return onTile.getItem(i);}
    //gets an item, but doesn't move it (for like, flipping switches)

//direction setters/getters
void setLoc(Location* i){loc = i;}
void setN(Tile* i){N = i;}
void setE(Tile* i){E = i;}
void setS(Tile* i){S = i;}
void setW(Tile* i){W = i;}
Location* getLoc(){return loc;}
Tile* getN(){return N;}
Tile* getE(){return E;}
Tile* getS(){return S;}
Tile* getW(){return W;}

//displays
void dispOnTile(){onTile.allDisplay();}
void dispSingle(int i){onTile.singleDisplay(i);}
};

I get the error message that "Container" and "Thing" are not defined. Why is this? The #includes look to me like they are coded correctly, and they've worked in the past. I assumed it might be an issue of the #included files being not end-bracketed correctly or not using the same namespace, but they are ended correctly (with a }; ) and they are using the standard namespace. What's up? I can't find an answer and I know it's got to be something simple. For the record, the #included files are below:

    #ifndef CONTAINER_H_INCLUDED
#define CONTAINER_H_INCLUDED
#include "Thing.h"
using namespace std;

class Container
{
private:
    Thing ** contents;  //array of pointers to Things
    int numItems;       //count item
    int maxSize;        //maxSize

public:
    //constructor
    Container(int i) {contents = new Thing*[i]; numItems = 0; maxSize=i;}
        //sets num of items (for set-size bags)
    Container() {contents = new Thing*[100]; numItems = 0; maxSize=100;}
        //creates array of things
    ~Container() {delete contents;}  //cleanup

//actions
bool addItem(Thing* th);    //adds item to bag (really just rereferences the pointer)
bool rmvItem(int i);        //removes item in array pos i
Thing* getItem(int i);      //returns a pointer to item at array pos i
Thing* movItem(int i);      //moves an item (deletes it and returns it)

//construction tools
void setMax(int i){delete contents; contents = new Thing*[i];}

//displays
void allDisplay();           //displays entire contents of container, numerated
void singleDisplay(int i);   //displays content item i

};

#endif // CONTAINER_H_INCLUDED

    #ifndef LOCATION_H_INCLUDED
#define LOCATION_H_INCLUDED
#include <string>
#include <sstream>
#include "Tile.h"
using namespace std;

class Location  //stores xy coordinates of something
{
int x;   //0 is NOT on map
int y;
Tile* ti;   //Locations contain pointers to tiles
public:
//constructors (mainly for debug)
Location(){x=y=0;}  //put object OUT OF MAP
Location(int ix, int iy){x=ix;y=iy;} //put object AT loc on map

//setters
void setX(int ix){x=ix;} //sets x
void setY(int iy){y=iy;} //sets y
void setT(Tile*i){ti=i;} //sets Tile

//getters
int getX() {return x;}
int getY() {return y;}
string getloc()     //return location as a string, separated by a comma
{
    ostringstream locxy;    //create stringstream obj to handle input
    locxy << getX() << "," << getY() << ". ";   //put x, space, y into stringstream
    string locret = locxy.str();        //convert stringstream to string
    return locret;                      //return string
    }
};

#endif // LOCATION_H_INCLUDED


    #ifndef THING_H_INCLUDED
#define THING_H_INCLUDED
#include <string>
#include "location.h"
using namespace std;

class Thing             //superclass that will be the base for objects
{
protected:
    Location * loc;     //location (in or out of map)
    string name;        //name
    string desc;        //description
    bool deletable;     //deletable (for undestructible items)
    bool takeable;      //if you can put it in your inv
    bool hasInv;        //returns true if the item has an inventory
public:
//constructor/destructor (debug only)
Thing() //sets initial values
    {loc = new Location(0, 0);
    name = "Uninitialized";
    deletable = takeable = true;
    }
Thing(int ix, int iy)  //sets location
    {loc = new Location(ix, iy);
    name = "Uninitialized";
    deletable = takeable = false;}
~Thing() {delete loc;}              //deletes allocated data

//getters
Location* getLoc() {return loc;}    //returns the location
string getDesc(){return desc;}      //returns the description
bool getDel(){return deletable;}    //returns deletable status
bool getTake(){return takeable;}    //returns takeable status
string getName(){return name;}      //returns name
string dispLoc(){return loc->getloc();} //displays location

//setters
void setName(string s){name = s;}   //sets name
void setDel(bool b){deletable = b;} //sets deletability
void setDesc(string d) {desc = d;}  //sets desc
void setLoc(Location* l) {loc = l;} //sets loc
void setTake(bool b){takeable = b;} //sets takeability

//accessors
};

#endif // THING_H_INCLUDED
4

2 回答 2

2

I believe this is because you have recursive dependincies. That is, your classes all depend on each other, which means that at some point one of the classes will not be able to compile, because in order to get compiled it will need declaration of a class, but, it will not be able to find the declaration, because it is in the header file that is already up there in the stack of "#include" and thus because of guarding "#ifdef" becomes empty.

To give you the example. To compile Tile, you need declaration of Location, so, naturally, you #include "location.h". But, to compile declaration of Location, you need declaration of Tile, so, you #include "Tile.h". But Tile.h has been #include-ed already, so there is no declaration for it!

The way to fight such circular dependencies is to use incomplete class declaration. For example, instead of including location.h into Tile.h, write

class Location;

class Tile
{
    Location* loc;
}

This works as long as Location is only used to declare a pointer or reference and no members of Location class are accessed.

Then, in you 'Tile.c' file you can #include "location.h" and allow your inplementation of Tile methods access to Location members.

于 2013-05-28T20:30:02.370 回答
1

You have an include-loop

  • Tile.h includes

    1. location.h
    2. Thing.h
    3. Container.h
  • Container.h includes Thing.h

  • Thing.h includes location.h

  • location.h includes Tile.h

Oops.

So let us say in the .cpp, the first to be included is Container.h. Then that includes Thing.h before it declares anything. Thing.h in turn includes location.h before it declares anything. Then that includes Tile.h before it declares anything. In Tile.h, all the include guards make the recursive includes no-ops.

And thus in Tile.h, Thing and Container are unknown.

于 2013-05-28T20:27:21.497 回答