недопустимое использование неполного описания типа / форварда - PullRequest
14 голосов
/ 09 августа 2011

Я пытался взглянуть на похожие проблемы, перечисленные здесь, в Stackoverflow и в Google, но они в основном касаются шаблонов, но это не мой случай.Я использую GCC 4.4.5 в Debian Testing 64bit.
Итак, у меня есть два класса - CEntity:

#ifndef CENTITY_H_INCLUDED
#define CENTITY_H_INCLUDED

#include "global_includes.h"

// game
#include "CAnimation.h"
#include "Vars.h"
#include "vector2f.h"
#include "Utils.h"

class CAnimation;

class CEntity
{
public:
    CEntity();
    virtual ~CEntity();

    void _update(Uint32 dt);

    void updateAnimation(Uint32 dt);

    void addAnimation(const std::string& name, CAnimation* anim);
    void addAnimation(const std::string& name, const CAnimation& anim);
    void removeAnimation(const std::string& name);
    void clearAnimations();

    bool setAnimation(const std::string& name);

    SDL_Surface* getImage() const;

    const vector2f& getPos() const;
    const vector2f& getLastPos() const;
    F getX() const;
    F getY() const;
    F getLastX() const;
    F getLastY() const;
    SDL_Rect* getHitbox() const;
    SDL_Rect* getRect() const;

    F getXSpeed() const;
    F getYSpeed() const;

    void setPos(const vector2f& pos);
    void setPos(F x, F y);
    void setPos(F n);
    void setX(F x);
    void setY(F y);

    void setHitboxSize(int w, int h);
    void setHitboxSize(SDL_Rect* rect);
    void setHitboxWidth(int w);
    void setHitboxHeight(int h);

    void setSpeed(F xSpeed, F ySpeed);
    void setXSpeed(F xSpeed);
    void setYSpeed(F ySpeed);

    void stop();
    void stopX();
    void stopY();

    void affectByGravity(bool affect);

    void translate(const vector2f& offset);
    void translate(F x, F y);

    bool collide(CEntity& s);
    bool collide(CEntity* s);

protected:
    CAnimation* mCurrentAnimation;
    SDL_Surface* mImage;

    vector2f mPos;
    vector2f mLastPos;
    SDL_Rect* mHitbox; // used for collisions
    SDL_Rect* mRect; // used only for blitting

    F mXSpeed;
    F mYSpeed;

    bool mAffByGrav;

    int mHOffset;
    int mVOffset;

private:
    std::map<std::string, CAnimation*> mAnims;
};

#endif // CENTITY_H_INCLUDED

и CPlayerChar, который наследуется от CEntity:

#ifndef CPLAYERCHAR_H_INCLUDED
#define CPLAYERCHAR_H_INCLUDED

#include "global_includes.h"

// game
#include "CEntity.h"

class CEntity;

class CPlayerChar : public CEntity
{
public:
    CPlayerChar();
    virtual ~CPlayerChar();

    virtual void update(Uint32 dt) = 0;

    virtual void runLeft() = 0;
    virtual void runRight() = 0;
    virtual void stopRunLeft() = 0;
    virtual void stopRunRight() = 0;

    virtual void attack() = 0;
    virtual void stopAttack() = 0;

    virtual void attack2() = 0;
    virtual void stopAttack2() = 0;

    virtual void ground() = 0;
    virtual void midair() = 0;

    void jump();
    void stopJump();

protected:
    // looking right?
    bool mRight;

    bool mJumping;
    bool mOnGround;
    bool mGrounded;
};

#endif // CPLAYERCHAR_H_INCLUDED

Когда я пытаюсь его скомпилировать, GCC выдает эту ошибку:

CPlayerChar.h:12: error: invalid use of incomplete type ‘struct CEntity’
CPlayerChar.h:9: error: forward declaration of ‘struct CEntity’

Сначала я попробовал это сделать без предварительного объявления 'class CEntity;'в CPlayerChar.h в строке 9, но тогда он выкинет это вместо

CPlayerChar.h:12: error: expected class-name before ‘{’ token

Так что там должно быть предварительное объявление.Кроме того, CEntity - это явно класс, а не структура.

Ответы [ 3 ]

9 голосов
/ 09 августа 2011

У вас есть циклическое включение в заголовочные файлы.
Но без всех заголовочных файлов мы не сможем это исправить.

Я бы начал здесь.

#include "CAnimation.h"

Глядя на ваш заголовок, вам на самом деле это не нужно.Вы используете CAnimation только по ссылке или по указателю, поэтому у вас должно быть достаточно предварительного объявления.Переместите включение в исходный файл (т.е. из заголовка).

Следующее место, которое я бы посмотрел, было:

#include "global_includes.h"

Любые глобальные включения, включенные в файл заголовка, лучшеочень просто.Должны содержать только простые типы и не включать никакие другие заголовочные файлы (если они не такие простые).Все сложное может привести к проблемам с циклическими зависимостями.

Общее практическое правило

Заголовочный файл должен включать только заголовочные файлы, которые ему абсолютно необходимы.В противном случае они должны быть включены из исходного файла.Файл заголовка вам абсолютно необходим, только если он определяет класс, который используется как родительский класс, у вас есть объекты-члены этого класса, или вы используете объекты параметров этого класса.

Я использую термин object дляотличать от ссылок или указателей.Если вы используете их, вам не нужно включать файл заголовка.Вам нужно только сделать предварительную декларацию.

6 голосов
/ 09 августа 2011

У вас, вероятно, есть цикл в ваших включениях таким образом, что CPlayerChar не знает, кто на самом деле CEntity, он просто знает, что он существует, но не знает, что это такое.

Если вы удалите объявление "class CEntity", вы увидите, что GCC будет жаловаться, что CEntity не существует.

Вы должны убедиться, что ничего, что включает в себя CEntity, не включает CPlayerChar.

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

Вы должны убедиться, что полное определение класса CEntity видно в точке, где вы определяете класс CPlayerChar. (Так что проверь свои включения.)

Это потому, что вы можете наследовать только от полностью определенных классов, но не от просто объявленных заранее.

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

...