Oru*_*aru 39 c++ header include-guards include
解决了
真正帮助我的是,我可以在.cpp文件中#include标头而不会导致重新定义的错误.
我是C++的新手,但我在C#和Java方面有一些编程经验,所以我可能会遗漏一些C++独有的基础知识.
问题是我真的不知道什么是错的,我会粘贴一些代码来试图解释这个问题.
我有三个类,GameEvents,Physics和GameObject.我有每个标题.GameEvents有一个Physics和一个GameObjects列表.Physics有一个GameObjects列表.
我想要实现的是我希望GameObject能够访问或拥有一个Physics对象.
如果我只是在GameObject中#include"Physics.h",我会得到"错误C2111:'ClassXXX':'class'类型redtifinition",我理解.这就是我认为#include-guard有帮助的地方所以我在我的Physics.h中添加了一个包含守卫,因为那是我想要包含两次的标题.
这是它的外观
#ifndef PHYSICS_H
#define PHYSICS_H
#include "GameObject.h"
#include <list>
class Physics
{
private:
double gravity;
list<GameObject*> objects;
list<GameObject*>::iterator i;
public:
Physics(void);
void ApplyPhysics(GameObject*);
void UpdatePhysics(int);
bool RectangleIntersect(SDL_Rect, SDL_Rect);
Vector2X CheckCollisions(Vector2X, GameObject*);
};
#endif // PHYSICS_H
Run Code Online (Sandbox Code Playgroud)
但如果我在GameObject.h中#include"Physics.h",现在就像这样:
#include "Texture2D.h"
#include "Vector2X.h"
#include <SDL.h>
#include "Physics.h"
class GameObject
{
private:
SDL_Rect collisionBox;
public:
Texture2D texture;
Vector2X position;
double gravityForce;
int weight;
bool isOnGround;
GameObject(void);
GameObject(Texture2D, Vector2X, int);
void UpdateObject(int);
void Draw(SDL_Surface*);
void SetPosition(Vector2X);
SDL_Rect GetCollisionBox();
};
Run Code Online (Sandbox Code Playgroud)
我得到了多个不明白为什么会出现的问题.如果我不#include"Physics.h"我的代码运行得很好.
我非常感谢任何帮助.
Sha*_*baz 119
预处理器是一个程序,它接受您的程序,进行一些更改(例如包括文件(#include),宏扩展(#define),基本上所有开始#
)并向编译器提供"干净"结果.
它看到时预处理器的工作原理如下#include
:
当你写:
#include "some_file"
Run Code Online (Sandbox Code Playgroud)
some_file
几乎字面上的内容被复制粘贴到包含它的文件中.现在,如果你有:
a.h:
class A { int a; };
Run Code Online (Sandbox Code Playgroud)
和:
b.h:
#include "a.h"
class B { int b; };
Run Code Online (Sandbox Code Playgroud)
和:
main.cpp:
#include "a.h"
#include "b.h"
Run Code Online (Sandbox Code Playgroud)
你得到:
main.cpp:
class A { int a; }; // From #include "a.h"
class A { int a; }; // From #include "b.h"
class B { int b; }; // From #include "b.h"
Run Code Online (Sandbox Code Playgroud)
现在您可以看到如何A
重新定义.
当你写警卫时,它们会变成这样:
a.h:
#ifndef A_H
#define A_H
class A { int a; };
#endif
b.h:
#ifndef B_H
#define B_H
#include "a.h"
class B { int b; };
#endif
Run Code Online (Sandbox Code Playgroud)
那么现在让我们来看看#include
main中的s是如何扩展的(这与前一种情况一样:copy-paste)
main.cpp:
// From #include "a.h"
#ifndef A_H
#define A_H
class A { int a; };
#endif
// From #include "b.h"
#ifndef B_H
#define B_H
#ifndef A_H // From
#define A_H // #include "a.h"
class A { int a; }; // inside
#endif // "b.h"
class B { int b; };
#endif
Run Code Online (Sandbox Code Playgroud)
现在让我们关注预处理器,看看是什么"真正的"代码.我会一行一行地去:
// From #include "a.h"
Run Code Online (Sandbox Code Playgroud)
评论.忽视!继续:
#ifndef A_H
Run Code Online (Sandbox Code Playgroud)
被A_H
定义?没有!然后继续:
#define A_H
Run Code Online (Sandbox Code Playgroud)
现在好了A_H
定义.继续:
class A { int a; };
Run Code Online (Sandbox Code Playgroud)
这不是预处理器的东西,所以请保留它.继续:
#endif
Run Code Online (Sandbox Code Playgroud)
以前if
在这里完成了.继续:
// From #include "b.h"
Run Code Online (Sandbox Code Playgroud)
评论.忽视!继续:
#ifndef B_H
Run Code Online (Sandbox Code Playgroud)
被B_H
定义?没有!然后继续:
#define B_H
Run Code Online (Sandbox Code Playgroud)
现在好了B_H
定义.继续:
#ifndef A_H // From
Run Code Online (Sandbox Code Playgroud)
被A_H
定义?是!然后忽略直到相应的#endif
:
#define A_H // #include "a.h"
Run Code Online (Sandbox Code Playgroud)
忽视
class A { int a; }; // inside
Run Code Online (Sandbox Code Playgroud)
忽视
#endif // "b.h"
Run Code Online (Sandbox Code Playgroud)
以前if
在这里完成了.继续:
class B { int b; };
Run Code Online (Sandbox Code Playgroud)
这不是预处理器的东西,所以请保留它.继续:
#endif
Run Code Online (Sandbox Code Playgroud)
以前if
在这里完成了.
也就是说,在预处理器完成文件之后,这就是编译器看到的内容:
main.cpp
class A { int a; };
class B { int b; };
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,任何可以#include
在同一文件中获取两次的内容,无论是直接还是间接都需要加以保护.由于.h
文件总是很可能被包含两次,所以如果你保护所有你的.h文件是好的.
PS注意你也有圆形#include
s.想象一下,预处理器将Physics.h的代码复制粘贴到GameObject.h中,后者看到有一个#include "GameObject.h"
复制GameObject.h
到自身的复制.当你复制时,你再次得到#include "Pysics.h"
并且你永远陷入了困境.编译器会阻止这种情况,但这意味着你#include
的工作已经完成了一半.
在说如何解决这个问题之前,你应该知道另一件事.
如果你有:
#include "b.h"
class A
{
B b;
};
Run Code Online (Sandbox Code Playgroud)
那么编译器需要知道的一切b
,最重要的是,它有哪些变量等,以便它知道它应该有多少字节落实到位b
的A
.
但是,如果你有:
class A
{
B *b;
};
Run Code Online (Sandbox Code Playgroud)
然后编译器并不需要知道任何事情B
(因为指针,无论类型是否具有相同的大小).它唯一需要知道的B
是它存在!
所以你做了一个叫做"前向声明"的事情:
class B; // This line just says B exists
class A
{
B *b;
};
Run Code Online (Sandbox Code Playgroud)
这与您在头文件中执行的许多其他操作非常相似,例如:
int function(int x); // This is forward declaration
class A
{
public:
void do_something(); // This is forward declaration
}
Run Code Online (Sandbox Code Playgroud)
你在这里有循环引用:Physics.h
包括GameObject.h
哪些包括Physics.h
.类Physics
用途GameObject*
(指针)类型,所以你并不需要包括GameObject.h
在Physics.h
,但只使用前向声明-而不是
#include "GameObject.h"
Run Code Online (Sandbox Code Playgroud)
放
class GameObject;
Run Code Online (Sandbox Code Playgroud)
此外,在每个头文件中放置警卫.
归档时间: |
|
查看次数: |
69685 次 |
最近记录: |