2013-04-20 4 views
1

Итак, мое текущее задание - сделать базовое моделирование Hunter and Prey, и после нескольких других вопросов мой профессор сообщил, что я просто поместил все в main.cpp, чтобы на самом деле получить вещь, работающая на данный момент.«Недопустимое использование неполного типа» в основных упражнениях Hunter/Prey

Моя текущая проблема заключается в том, что в функции Creature::Find() она заявляет, что класс Grid является неполным, хотя он предварительно объявлен в верхней части файла. Моя первоначальная мысль заключалась в том, чтобы поместить класс Grid до Creature, но это приводит к гораздо большей или той же ошибке (ссылаясь на Creature, будучи неполным), поскольку Grid по существу является двумерным массивом указателей Creature. Ниже приведены соответствующие биты кода, весь файл можно найти в 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; 
    } 
}; 

EDIT: Предварительный просмотр и панель инструментов разметки не работает по какой-то причине.

ответ

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

+0

@Farlo Нет, предварительная декларация (обычно называемая прямым объявлением) сообщает компилятору, что Grid является классом, поэтому (например) 'Grid * theGrid;' является законным. Но передняя декларация не сообщает компилятору ничего о * классе. Таким образом, 'theGrid-> Occupant (temp)' не является законным даже после прямого объявления, потому что в прямом объявлении не сообщается компилятору, что у Grid есть метод под названием Occupant – john

+0

@Farlo. Проблема, которую обычно можно избежать, гарантируя реализацию * * любого кода, который использует неполные типы, следует декларации, которая завершает тип.В этом случае нет ничего, что помешало бы вам переместить реализацию метода «Существо :: Find» вне класса (просто объявите его как член, не реализуйте его в классе) и реализуйте его * после * формального определение 'Grid'. И +1 на ответ. – WhozCraig

0

Вперед декларация подходит для объявления указателя. Однако компилятор не знает, что еще сказал ваш объявленный вперед класс. Таким образом, вы не можете ожидать, что это позволить что-то вроде

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

Вам нужно либо включить файл, который содержит все определения сетки. ИЛИ вы можете переместить определение функции Creature::find в другой файл, где включен Grid.h. Например, в Grid.cpp

+0

Его нельзя перемещать в другой файл и, конечно же, не перемещать в файл, совершенно не связанный по имени. До тех пор, пока код, использующий то, что было неполным типом во время объявления, следует за формальным объявлением для завершения типа, оно будет работать даже в том же исходном файле. – WhozCraig

+0

@WhozCraig Я сказал, что он может включать файл, содержащий полное определение Grid. Я не знаю, что вы имеете в виду? – stardust

+0

@WhozCraig и не зависит от того, является ли имя файла релевантным или нет. Это просто ** пример **. он говорит, например, прямо там. – stardust