Подтвердить что ты не робот

Недопустимое использование неполного типа/форвардной декларации

Я попытался рассмотреть аналогичные проблемы, перечисленные здесь в 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 явно является классом, а не структурой.

4b9b3361

Ответ 1

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

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

#include "CAnimation.h"

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

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

#include "global_includes.h"

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

Общее правило большого пальца

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

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

Ответ 2

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

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

Вы должны проверить, что ничего, что включает CEntity, включает CPlayerChar.

Ответ 3

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

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

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