Дилемма ошибки наследования: «недопустимое использование неполного типа» VS «ожидаемое имя класса» - PullRequest
2 голосов
/ 02 августа 2011

Поэтому я пытаюсь получить класс "Гердер", чтобы унаследовать от класса "Моб". Но я получаю ошибки компилятора, которые выглядят следующим образом:

error: invalid use of incomplete type 'struct Mob'
error: forward declaration of 'struct Mob'

Вот как выглядит Herder.h:

#ifndef HERDER_H_INCLUDED
#define HERDER_H_INCLUDED

#include <SFML/Graphics.hpp>
#include <cstdlib>
#include "Level.h"
#include "Mob.h"

class Mob;

class Herder : public Mob
{
public:
    //Member functions.
    Herder(Level* level, int x, int y);
    void virtual GameCycle(sf::RenderWindow* App);
    void virtual Die();
    void Roar();
protected:
    float m_RoarCountdown;
    float m_RoarTime;
    float m_Speed;
    bool m_Roaring;
};

#endif // HERDER_H_INCLUDED

Предполагая, что это должно быть class Mob;, что вызывает это, я удаляю его, но затем получаю следующую ошибку, ссылаясь на строку, где открываются фигурные скобки:

error: expected class-name before '{' token

Именно поэтому я первоначально добавил предварительное объявление - я думал, что компилятор не распознает Mob в class Herder : public Mob, поэтому я решил, что я буду отправлять объявление.

Я не думаю, что это случай циклической зависимости, как это было в некоторых случаях, которые я обнаружил через Google - "Mob.h" не имеет ничего общего с классом Herder.

Я попытался удалить #include "Mob.h" в целом и придерживаться только предварительного объявления, но это тоже не работает - я снова получаю только одну ошибку:

error: invalid use of incomplete type 'struct Mob'

Это сбивает с толку. Я успешно получил классы для наследования и раньше, и этот код во всех моих предыдущих успешных попытках аналогичен во всех соответствующих отношениях.


РЕДАКТИРОВАТЬ: Вот содержание Mob.h

#ifndef MOB_H_INCLUDED
#define MOB_H_INCLUDED

#include <SFML/Graphics.hpp>
#include <cstdlib>
#include "Level.h"

class Level;

class Mob
{
public:
    //Member functions.
    Mob(Level* level, int x, int y);
    float GetX();
    float GetY();
    void SetColor(sf::Color color);
    void virtual GameCycle(sf::RenderWindow* App) = 0;
    void virtual Die() = 0;
    void Draw(sf::RenderWindow* App);
protected:
    float m_X;
    float m_Y;
    bool m_Moving;
    int m_Health;
    sf::Sprite m_Sprite;
    Level* pLevel;
};

#endif // MOB_H_INCLUDED

РЕДАКТИРОВАТЬ: Вот содержимое файла "Level.h". Обратите внимание, что Baby является дочерним классом Mob во многом так же, как Herder; оба имеют одинаковые ошибки.

#ifndef LEVEL_H_INCLUDED
#define LEVEL_H_INCLUDED

#include <SFML/Graphics.hpp>
#include <cstdlib>
#include "Tile.h"
#include "Herder.h"
#include "Baby.h"

class Tile;
class Herder;
class Baby;

/// LEVEL
/// This is the collection of all data regarding a level, including layout, objects, mobs, and story elements.
///

class Level
{
public:
    //Constructor
    Level(int height, int width, std::string name);
    //For obtaining positional data
    int GetHeight();
    int GetWidth();
    std::string GetName();
    sf::Image GetTileImage(int image);
    sf::Image GetMobImage(int image);
    std::vector< std::vector<Tile> >& GetGrid();
    void NewHerder(int x, int y);
    void NewBaby(int x, int y);
    void GameCycle(sf::RenderWindow* App);
    void GraphicsCycle(sf::RenderWindow* App);
private:
    //Size
    int m_Height;
    int m_Width;
    //Spatial coords
    std::string m_Name;
    //The grid of tiles.
    std::vector< std::vector<Tile> > m_Grid;
    //A vector of the images to be used for tiles.
    std::vector<sf::Image> m_TileImages;
    //A vector of the images to be used for tiles.
    std::vector<sf::Image> m_MobImages;
    //The herders
    std::vector<Herder> m_Herders;
    //The babies
    std::vector<Baby> m_Babies;
};

#endif // LEVEL_H_INCLUDED

РЕДАКТИРОВАТЬ: Преимущественно, вот содержимое Tile.h:

#ifndef TILE_H_INCLUDED
#define TILE_H_INCLUDED

#include <SFML/Graphics.hpp>
#include <cstdlib>
#include "Level.h"

class Level;

/// TILE
/// This is the basic environmental unit in the game
///

class Tile
{
public:
    //Constructor
    Tile(int col, int row, int size, int type, Level* level);
    //For obtaining positional data
    int GetX();
    int GetY();
    int GetRow();
    int GetCol();
    //For obtaining type data
    int GetType();
    //For obtaining string type data
    std::string GetStringType();
    //For changing type data
    void SetType(int type);
    void SetStringType(std::string character);
    //For activities that regularly take place
    void GameCycle();
    //Draws the tile.
    void Draw(sf::RenderWindow* App);
private:
    //The level this tile belongs to.
    Level* m_Level;
    //Size (it's a square!)
    int m_Size;
    //Spatial coords
    int m_X;
    int m_Y;
    //Grid coords
    int m_Row;
    int m_Col;
    //Type
    int m_Type;
    //Visual data
    sf::Sprite m_Tile;
};

#endif // TILE_H_INCLUDED

Ответы [ 3 ]

7 голосов
/ 02 августа 2011

Это циклическая зависимость (Herder.h включает Level.h, который включает Herder.h и т. Д.).

В Herder.h просто замените это:

#include "Level.h"

с:

class Level;

и сделать то же самое в Mob.h

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

4 голосов
/ 02 августа 2011

У вас проблема с циклической зависимостью, которая является запахом кода.С одной стороны, чтобы иметь возможность наследования от типа, базовое определение должно быть доступно для компилятора (т. Е. Компилятору требуется полностью определенный тип для наследования).С другой стороны, ваш базовый класс зависит от производного класса.

Технический ответ заключается в прямом объявлении производного типа (чтобы вы могли определить базу), а затем в определении базы,Но вы должны подумать о том, что вы делаете: почему эти два отдельных типа связаны наследованием?Почему не один?Или три (разделить обязанности)?Если база зависит от производного для его собственного интерфейса, это указывает на то, что они слишком сильно связаны.Переосмыслите дизайн.

0 голосов
/ 02 августа 2011

"Herder.h" и "Level.h" - это #include друг в друге.Итак, я думаю, что эта ошибка исходит от "Herder.h", который включен первым.Это становится циклическим.Удалите это и посмотрите, исчезнет ли ошибка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...