开发者

Inheritance error dilemma: "invalid use of incomplete type" VS "expected class-name"

So I'm trying to get class "Herder" to inherit from class "Mob". But I am getting compiler errors that read as follows:

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

This is what Herder.h looks like:

#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

Figuring that it must be the class Mob; that is causing this, I remove it, but then I get the following error, refering to the line where the curly braces open:

error: expected class-name before '{' token

This is actually why I originally added the forward declaration - I had thought that the compiler wasn't recognizing Mob in class Herder : public Mob, so I figured I would forward declare.

I don't think it's a case of cyclical dependency, as has been the case in some cases I found via Google - "Mob.h" contains nothing to do with the Herder class whatsoever.

I have tried removing #include "Mob.h" altogether and sticking with just the forward declaration, but that doesn't work either - I get only one error, again:

error: invalid use of incomplete type 'struct Mob'

This is confusing. I've successfully gotten classes to inherit before, and this code seems analogous in all relevant ways to my previous successful attempts.


EDIT: 开发者_Go百科 Here are the contents of 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

EDIT: Here are the contents of the "Level.h" file. Note that Baby is a child class of Mob in much the same way as Herder; both experience the same errors.

#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

EDIT: Pre-emptively, here are the contents of 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


It is a cyclic dependency (Herder.h includes Level.h which includes Herder.h, etc.).

In Herder.h, simply replace this :

#include "Level.h"

with :

class Level;

and do the same in Mob.h

The general rule is to include as little header files as possible (ie. only the ones you need). If you can get by with a forward declaration eg., then use that rather than a full include.


The problem you have is a cyclic dependency which is a code smell. On the one side, to be able to derive from a type, the base definition must be available to the compiler (i.e. the compiler requires a fully defined type from which to inherit). On the other hand your base class depends on the derived class.

The technical answer is to forward declare the derived type (so that you can define the base), and then define the base. But you should really think on what you are doing: why are those two separate types related by inheritance? Why not one? Or three (split responsibilities)? If the base depends on the derived for it's own interface, that seems to indicate that they are too highly coupled. Rethink the design.


"Herder.h" and "Level.h" are #include in each other. So, I think this error is coming from the "Herder.h" which is included first. It's becoming cyclic. Remove that and see if the error goes away.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜