2013-04-20 69 views
1

所以我目前的任务是做一个基本的猎人与猎物的模拟,以及具有其它几个问题后,我的教授建议,我只是把一切都放在main.cpp实际得到的现在工作的东西。“无效使用不完全类型的”

我目前的问题是,在Creature::Find()函数声称Grid类是不完整的,即使它是预先声明在文件的顶部。我最初的想法是在Creature之前放置Grid类,但这会导致更多或相同的错误(指Creature不完整),因为Grid本质上是指针的二维数组。下面是代码的相关位,整个文件可以在Dropbox here上找到。


class Grid; //*** error: forward declaration of 'class Grid' 

//Other stuff... 

class Creature 
{ 
public: 
    Grid* theGrid; 
    Coords position; 
    int stepBreed; 
    int stepHunger; 
    char face; 
    bool hasMoved; 

    Creature(Grid* _grid, Coords _position, char _face) //Constructor 
    { 
     theGrid = _grid; 
     position = _position; 
     face = _face; 
     stepBreed = stepHunger = 0; 
     hasMoved = false; 
    } 

    vector<Coords> Find(char thisFace) //Returns a list of coords with prey on them 
    { 
     vector<Coords> result; 
     for(int i = position.x-1; i <= position.x+1; i++) 
      for(int j = position.y-1; j <= position.y+1; j++) 
      { 
       Coords temp(i,j); 
       if(theGrid->Occupant(temp) == thisFace) //*** error: invalid use of incomplete type 'class Grid' 
        result.push_back(temp); 
      } 
     return result; 
    } 

    virtual Coords Move() = 0; //Allows the creature type to define it's own movement 
    virtual Coords Breed() = 0; //Allows the creature type to define it's own breeding 
    virtual bool Starve() = 0; //Allows the creature type to starve of its own accord 
}; 

class Grid 
{ 
public: 
    Creature* grid[MAX_X][MAX_Y]; 

    Grid() //Initalizes the grid and spawns random creatures 
    { 
     cout<<endl<<"grid init"<<endl; 
     for(int i = 0; i < MAX_X; i++) 
      for(int j = 0; j < MAX_Y; j++) 
       grid[i][j] = NULL; 
    } 

    void Move() //Tells each creature on the grid to move 
    { 
     cout<<endl<<"--- Grid::Move() TOP ---"<<endl<<endl; 
     ResetMoved(); 

     for(int i = 0; i < MAX_X; i++) 
      for(int j = 0; j < MAX_Y; j++) 
       if(grid[i][j]) 
        grid[i][j]->Move(); 
     cout<<endl<<"--- Grid::Move() BOTTOM ---"<<endl<<endl; 
    } 

    void Breed() //Tells each creature to breed (if it can) 
    { 

    } 

    void Kill() //Tells each creature to die (if it's old) 
    { 

    } 

    char** Snapshot() //Creates a char array "snapshot" of the board 
    { 
     char** result = new char*[MAX_X]; 
     for(int i = 0; i < MAX_X; i++) 
     { 
      result[i] = new char[MAX_Y]; 
      for(int j = 0; j < MAX_Y; j++) 
      { 
       result[i][j] = Occupant(Coords(i, j)); 
      } 
     } 
     return result; 
    } 

    Creature* Get(Coords here) //Returns a pointer to the object at the specified position 
    { 
     return grid[here.x][here.y]; 
    } 

    char Occupant(Coords here) //Returns the character of the specified position 
    { 
     if(!Get(here)) 
      return FACE_EMPTY; 
     return Get(here)->face; 
    } 

    void Clear(Coords here) //Deletes the object at the specified position 
    { 
     cout<<endl<<"--- Grid::Clear() TOP ---"<<endl<<endl; 

     if(!Get(here)) 
     { 
      cout<<" inside if"<<endl; 
      delete Get(here); 
     } 
     cout<<" outside if"<<endl; 
     grid[here.x][here.y] = NULL; 

     cout<<endl<<"--- Grid::Clear() BOTTOM ---"<<endl<<endl; 
    } 

    void ResetMoved() 
    { 
     for(int i = 0; i < MAX_X; i++) 
      for(int j = 0; j < MAX_Y; j++) 
       if(grid[i][j]) 
        grid[i][j]->hasMoved = false; 
    } 
}; 

编辑:预览和标记工具栏不工作的一些原因。

回答

3

你有一个循环依赖(我好像记得你以前有这个问题)。把东西放在同一个文件中并不能真正解决问题(尽管也许它可以帮助你更清楚地看到问题)。你必须做的是正确地排列事物,以便每个函数都在它需要的类之后定义。

在这种情况下,我会做这样的

class Grid; 

class Creature 
{ 
public: 
    Grid* theGrid; 
    ... 
    vector<Coords> Find(char thisFace); 
    ... 
}; 

class Grid 
{ 
public: 
    Creature* grid[MAX_X][MAX_Y]; 
    ... 
}; 

vector<Coords> Creature::Find(char thisFace) 
{ 
    ... 
} 

Creature::Find需要两个Creature类(明显)和Grid类,所以后两个类已经完全确定它莫属。

如果最终将Creature::Find定义放在头文件中,那么您必须添加inline关键字,否则您将获得多个定义。

+0

呀,抱歉关于制造新的问题类似的主题,就是不知道这是否必要了。我在各种职能上得到了未解决的外部问题,教授也无法弄清楚为什么要这样做,这就是为什么他让我把所有的东西都放在主体中。我认为Grid的预先声明是为了防止这样的东西,还是只适用于定义? – Farlo 2013-04-20 06:56:21

+0

@Farlo不,预申报(通常称为正向声明)告诉编译器,电网是一个类,所以(例如)'电网* theGrid;'是合法的。但是前向声明并没有告诉编译器关于类的任何事情。所以'theGrid->乘员(临时)'是不合法的,甚至向前声明之后,因为前声明不告诉网格有一个名为乘员 – john 2013-04-20 06:58:54

+0

方法@Farlo你通常可以通过确保*实现避免的一个问题,编译器*任何使用不完整类型的代码都遵循完成类型的声明。在这种情况下,没有任何东西可以阻止你在课堂之外移动执行'Creature :: Find'方法(只是将它声明为一个成员,不要在类中实现)并且在*正式'Grid'的定义。并在答案+1。 – WhozCraig 2013-04-20 07:00:59

0

远期声明是罚款声明的指针。然而,编译器不知道你的转发声明类包含了什么。所以你不能指望它能够像

class Grid; 
// 
theGrid->Occupant(temp) 

您需要可以包括其中包含电网的整个定义的文件。或您可以将Creature::find函数的定义移动到包含Grid.h的另一个文件中。例如,在Grid.cpp

+0

它不需要移动到另一个文件,当然也不会移动到与名称无关的文件。只要在声明过程中利用不完整类型的代码遵循正式声明来完成该类型,即使在同一个源文件中,它也可以工作。 – WhozCraig 2013-04-20 07:04:12

+0

@WhozCraig我曾经说过他可以包含包含网格整个定义的文件。我不知道你的意思? – stardust 2013-04-20 07:14:54

+0

@WhozCraig以及文件名是否相关不取决于我自己决定。这只是一个**示例**。它就是这样说的。 – stardust 2013-04-20 07:16:37