不完整类型/前向声明的无效使用
我尝试查看 Stackoverflow 和 Google 上列出的类似问题,但它们主要处理模板,而这不是我的情况。我在 Debian 测试 64 位上使用 GCC 4.4.5。
所以,我有两个类 - 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;' 的情况下尝试了它在第 9 行 CPlayerChar.h 中,但随后它会抛出 this ,
CPlayerChar.h:12: error: expected class-name before ‘{’ token
所以前向声明必须在那里。另外,CEntity 显然是一个类,而不是一个结构。
I tried to look at the similar problems listed here on Stackoverflow and on Google but they deal mostly with templates and that's not my case. I'm using GCC 4.4.5 on Debian Testing 64bit.
So, I have two classes - 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
and CPlayerChar which inherits from 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
When I try to compile it, GCC throws this error:
CPlayerChar.h:12: error: invalid use of incomplete type ‘struct CEntity’
CPlayerChar.h:9: error: forward declaration of ‘struct CEntity’
I tried it first without the forward declaration 'class CEntity;' in CPlayerChar.h on line 9, but then it would throw this instead
CPlayerChar.h:12: error: expected class-name before ‘{’ token
So the forward declaration has to be there. Also, CEntity is clearly a class, not a struct.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的头文件中存在循环包含。
但如果没有所有头文件,我们将无法修复它。
我会从这里开始。
看看你的标题,你实际上并不需要这个。您仅通过引用或指针使用 CAnimation,因此您拥有的前向声明应该足够了。将包含内容移至源文件中(即移出标头)。
我要查看的下一个地方是:
头文件中包含的任何全局包含最好非常简单。应该只包含简单类型,而不包含任何其他头文件(除非它们同样简单)。任何复杂的事情都会导致循环依赖问题。
一般经验法则
头文件应该只包含它绝对需要的头文件。否则,它们应该包含在源文件中。如果头文件定义了一个用作父类的类,并且您拥有该类的成员对象,或者使用该类的参数对象,那么您绝对需要一个头文件。
我使用术语
对象
来区别引用或指针。如果您使用这些,则不需要包含头文件。您只需要进行前向声明即可。You have a circular inclusion in your header files.
But without all the header files we will not be able to fix it.
I would start here.
Looking at your header you don't actually need this. You only use CAnimation by reference or pointer so the forward declaration you have should be sufficient. Move the include into the source file (ie out of the header).
The next place I would look is:
Any global includes that are included in a header file better be very simple. Should only contain simple types and not include any other header files (unless they are just as simple). Anything complex is going to lead to problems with circular dependencies.
General rule of thumb
A header file should only include header files that it absolutely needs. Otherwise they should be included from the source file. You only absolutely need a header file if it defines a class that is used as a parent class you have members objects of that class, or you use parameter objects of that class.
I use the term
object
to distinguish from references or pointers. If you are using these you do not need to include the header file. You only need to do a forward declaration.您的包含中可能有一个循环,使得 CPlayerChar 不知道谁真正是 CEntity,它只知道它存在,但不知道它是什么。
如果删除“class CEntity”声明,您将看到 GCC 会抱怨 CEntity 不存在。
您必须检查 CEntity 中是否没有包含 CPlayerChar。
You probably have got a loop in your includes in such way that CPlayerChar doesnt know who really is CEntity, it just knows that it exists, but doesnt know what is it.
If you remove the "class CEntity" declaration, you will see that GCC will complain that CEntity doesnt exists.
You must check that nothing that CEntity includes include CPlayerChar.
您必须确保类
CEntity
的完整定义在您定义类CPlayerChar
时可见。 (因此请检查您的包含内容。)这是因为您只能从完全定义的类继承,而不能从前向声明的类继承。
唯一可以用前向声明代替完整定义的情况是当您对类型进行指针或引用时,但前提是您从不访问其任何成员,或者(感谢@Alf)在使用返回类型不完整。
You have to ensure that the full definition of the class
CEntity
is visible at the point where you define the classCPlayerChar
. (So check your inclusions.)This is because you can only inherit from fully defined classes, but not from just forward-declared ones.
The only time you can get away with forward-declarations in place of full definitions is when you make pointers or references to a type, but only if you never access any of its members, or (thanks to @Alf) when declaring a function with incomplete return type.