无效地使用不完整的类型/前向声明
invalid use of incomplete type / forward declaration
我试着看看在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)当声明一个返回类型不完整的函数时。
- std::enable_if 更改成员 *变量* 声明/类型
- 对前向声明类型进行unique_ptr的解决方法
- 如何将声明类型作为参数发送
- 在 Fortran 中泛化特定声明类型的操作
- 使用 (c++11) 声明类型时放置 __declspec(dllimport) 关键字的位置
- 模板函数可以使用带有删除的构造函数的声明类型
- 声明类型没有任何可变类型
- 如何使用声明类型简化此代码
- 使用声明类型选择函数专业化
- 替代班级内声明类型的别名
- 对于自动键入推论的参数,声明类型(自动)应推导的内容
- 使用 decltype 的条件声明类型
- 您如何声明类型结构的堆栈?在C 中
- 将指向前向声明类型的指针推送到 typedef'd 向量时出现编译器错误
- 声明适用于 auto,但不能显式声明类型?
- 声明类型包含未展开的参数包'Args'
- 课堂上的Typedef.在另一个类错误中:尚未声明类型
- 冲突的声明类型/价值不匹配
- 获取具有AST访问者clang的功能声明类型
- 变量声明类型定义 C 中的约定