2013-04-20 73 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