无效地使用不完整的类型/前向声明

invalid use of incomplete type / forward declaration

本文关键字:声明 类型 用不完 无效      更新时间:2023-10-16

我试着看看在Stackoverflow和Google上列出的类似问题,但他们主要处理模板,这不是我的情况。我使用GCC 4.4.5在Debian测试64位。
所以,我有两个类- 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

和继承自CEntity的CPlayerChar:

#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’

我首先尝试了它,没有在第9行CPlayerChar.h中的前向声明'class CEntity;',但随后它会抛出这个而不是

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

所以forward声明必须在那里。另外,CEntity显然是一个类,而不是一个结构体。

头文件中有一个循环包含。
但是没有所有的头文件,我们将无法修复它。

我会从这里开始。

#include "CAnimation.h"

看看你的标题,你实际上不需要这个。您只能通过引用或指针使用动画,因此您拥有的前向声明应该足够了。将包含内容移到源文件中(即从头文件中移出)。

下一个要看的地方是:

#include "global_includes.h"

任何包含在头文件中的全局包含最好非常简单。应该只包含简单类型,而不包括任何其他头文件(除非它们同样简单)。任何复杂的东西都会导致循环依赖的问题。

一般经验法则

头文件应该只包含它绝对需要的头文件。否则,它们应该从源文件中包含。只有当头文件定义的类用作父类时,才绝对需要头文件,该类具有该类的成员对象,或者使用该类的参数对象。

我使用术语object来区别于引用或指针。如果使用这些,则不需要包含头文件。你只需要做一个前向声明。

你可能在你的include中有这样一个循环,CPlayerChar不知道谁是真正的CEntity,它只知道它存在,但不知道它是什么

如果你删除"class CEntity"声明,你会看到GCC会报错CEntity不存在。

你必须检查CEntity包含的任何东西都不包含CPlayerChar。

您必须确保在定义类CPlayerChar时,类CEntity的完整定义是可见的。(所以请检查您的包含内容。)

这是因为你只能从完全定义的类继承,而不能只从前声明的类继承。

你可以用前向声明代替完整定义的唯一情况是当你对一个类型做指针或引用时,但只有当你从不访问它的任何成员时,或者(多亏了@Alf)当声明一个返回类型不完整的函数时。