C ++ #include guard [英] C++ #include guards
问题描述
已解决
真正帮助我的是,我可以在.cpp文件中使用#include头文件,导致重新定义的错误。
我是C ++的新手,但是我在C#和Java上有一些编程经验,所以我可能会缺少一些C ++独有的基本知识。
问题是我真的不知道是什么问题,我会粘贴一些代码来尝试解释这个问题。
我有三个类,GameEvents,Physics和GameObject。我有每个的标题。
GameEvents有一个Physics和一个GameObjects列表。
物理学有一个GameObjects列表。
我想要实现的是我想要GameObject能够访问或拥有一个物理对象。 / p>
如果我只是#includePhysics.h在GameObject中我得到
错误C2111:'ClassXXX':'类'类型redifinition 。
这是我认为#include-guard可以帮助我的地方,所以我添加了一个包括守卫我的Physics.h,因为这是头部我想包括两次。
这是它的外观
#ifndef PHYSICS_H
#define PHYSICS_H
# includeGameObject.h
#include< list>
类物理学
{
private:
double gravity;
list< GameObject *>对象;
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
但是如果我#includePhysics。 hin my GameObject.h现在像这样:
#includeTexture2D.h
#includeVector2X .h
#include< SDL.h>
#includePhysics.h
class GameObject
{
private:
SDL_Rect collisionBox;
public:
Texture2D纹理;
Vector2X位置;
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();
};
我遇到了多个问题,不明白为什么会出现。
如果我不#includePhysics.h,我的代码运行正常。
我非常感谢任何帮助。
预处理器是一个程序,它接受您的程序,进行一些更改(例如包含文件(#include),宏扩展(#define) ,以及基本上以#
开头的所有内容),并将clean结果提供给编译器。
当它看到 #include
:
当你写:
#includesome_file
some_file
的内容几乎逐字地将副本粘贴到包括它的文件中。现在如果你有:
a.h:
class A {int a; };
和:
bh:
#includeah
class B {int b; };
和:
code> main.cpp:
#includeah
#includebh
b $ b
你得到:
main.cpp:
class A {int a; }; // From #includea.h
class A {int a; }; // From #includeb.h
class B {int b; }; // From #includebh
现在你可以看到 A
重新定义。
当你写守卫时,它们变成这样:
ah:
#ifndef A_H
#define A_H
class A {int a; };
#endif
b.h:
#ifndef B_H
#define B_H
#includea.h
class B {int b; };
#endif
现在让我们看看 #include
s将在main中扩展(这正是像前面的情况一样:复制粘贴)
main.cpp:
//从#includeah
#ifndef A_H
#define A_H
class A {int a; };
#endif
//从#includebh
#ifndef B_H
#define B_H
#ifndef A_H //从
#define A_H / / #includeah
class A {int a; }; // inside
#endif //b.h
class B {int b; };
#endif
现在让我们来看看预处理器,看看什么是真正的代码这个。我将一行一行:
//从#includeah
注释。忽视!继续:
#ifndef A_H
$ b b
是否定义了 A_H
?没有!然后继续:
#define A_H
现在确定 A_H
。继续:
class A {int a; };
这不是预处理器的东西,所以只是保留。继续:
#endif
前面的如果
在这里完成。继续:
//从#includebh
注释。忽视!继续:
#ifndef B_H
是否定义了 B_H
?没有!然后继续:
#define B_H
现在确定 B_H
。继续:
#ifndef A_H // From
是否定义了 A_H
?是!然后忽略直到相应的 #endif
:
#define A_H //# includeah
忽略
class A {int a; }; // inside
忽略
#endif //bh
> if 完成这里。继续:
class B {int b; };
这不是预处理器的东西,所以只是保留。继续:
#endif
前面的 if
在这里完成。
该文件,这是编译器看到的:
main.cpp
class A {int a; };
class B {int b; };
如你所见,任何可以获得 #include
d在同一个文件中两次,无论是直接还是间接需要保护。由于 .h
文件总是很可能被包含两次,所以如果你保护所有的.h文件,这是很好的。
PS注意,你也有圆形 #include
。想象一下将Physics.h的代码复制粘贴到GameObject.h中的预处理器,它看到有一个 #includeGameObject.h
这意味着复制 GameObject.h
进入自己。当你复制时,你再次得到 #includePysics.h
,你永远陷入一个循环。编译器阻止,但这意味着你的 #include
已经完成。
在说如何解决这个问题
如果你有:
#includebh
class A
{
B b;
};
然后编译器需要知道 b
,最重要的是,它有什么变量等等,以便它将知道应该放置多少字节 b
在 A
。
但是,如果您有:
A
{
B * b;
};
然后编译器真的不需要知道 B
(因为指针,不管类型是否具有相同的大小)。只需要知道
B
就是它存在!
所以你做一些名为forward declaration :
B类; //这行只是说B存在
class A
{
B * b;
};
这与头文件中的许多其他操作非常相似,例如:
int function(int x); //这是向前声明
class A
{
public:
void do_something(); //这是向前声明
}
SOLVED
What really helped me was that I could #include headers in the .cpp file with out causing the redefined error.
I'm new to C++ but I have some programming experience in C# and Java so I could be missing something basic that's unique to C++.
The problem is that I don't really know what's wrong, I will paste some code to try to explain the issue.
I have three Classes, GameEvents, Physics and GameObject. I have headers for each of them. GameEvents has one Physics and a list of GameObjects. Physics has a list of GameObjects.
What I'm trying to achieve is that I want GameObject to be able to access or own a Physics object.
If I simply #include "Physics.h" in GameObject I get the "error C2111: 'ClassXXX' : 'class' type redifinition" which I understand. And this is where I thought #include-guards would help so I added an include guard to my Physics.h since that's the header I want to include twice.
This is how it looks
#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
But if I #include "Physics.h" in my GameObject.h now like this:
#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();
};
I get multiple issues that don't understand why they're showing up. If I don't #include "Physics.h" my code runs just fine.
I'm very grateful for any help.
The preprocessor is a program that takes your program, makes some changes (for example include files (#include), macro expansion (#define), and basically everything that starts with #
) and gives the "clean" result to the compiler.
The preprocessor works like this when it sees #include
:
When you write:
#include "some_file"
The contents of some_file
almost literally get copy pasted into the file including it. Now if you have:
a.h:
class A { int a; };
And:
b.h:
#include "a.h"
class B { int b; };
And:
main.cpp:
#include "a.h"
#include "b.h"
You get:
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"
Now you can see how A
is redefined.
When you write guards, they become like this:
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
So now let's look at how #include
s in main would be expanded (this is exactly, like the previous case: 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
Now let's follow the preprocessor and see what "real" code comes out of this. I will go line by line:
// From #include "a.h"
Comment. Ignore! Continue:
#ifndef A_H
Is A_H
defined? No! Then continue:
#define A_H
Ok now A_H
is defined. Continue:
class A { int a; };
This is not something for preprocessor, so just leave it be. Continue:
#endif
The previous if
finished here. Continue:
// From #include "b.h"
Comment. Ignore! Continue:
#ifndef B_H
Is B_H
defined? No! Then continue:
#define B_H
Ok now B_H
is defined. Continue:
#ifndef A_H // From
Is A_H
defined? YES! Then ignore until corresponding #endif
:
#define A_H // #include "a.h"
Ignore
class A { int a; }; // inside
Ignore
#endif // "b.h"
The previous if
finished here. Continue:
class B { int b; };
This is not something for preprocessor, so just leave it be. Continue:
#endif
The previous if
finished here.
That is, after the preprocessor is done with the file, this is what the compiler sees:
main.cpp
class A { int a; };
class B { int b; };
So as you can see, anything that can get #include
d in the same file twice, whether directly or indirectly needs to be guarded. Since .h
files are always very likely to be included twice, it is good if you guard ALL your .h files.
P.S. Note that you also have circular #include
s. Imagine the preprocessor copy-pasting the code of Physics.h into GameObject.h which sees there is an #include "GameObject.h"
which means copy GameObject.h
into itself. When you copy, you again get #include "Pysics.h"
and you are stuck in a loop forever. Compilers prevent that, but that means your #include
s are half-done.
Before saying how to fix this, you should know another thing.
If you have:
#include "b.h"
class A
{
B b;
};
Then the compiler needs to know everything about b
, most importantly, what variables it has etc so that it would know how many bytes it should put in place of b
in A
.
However, if you have:
class A
{
B *b;
};
Then the compiler doesn't really need to know anything about B
(since pointers, regardless of the type have the same size). The only thing it needs to know about B
is that it exists!
So you do something called "forward declaration":
class B; // This line just says B exists
class A
{
B *b;
};
This is very similar to many other things you do in header files such as:
int function(int x); // This is forward declaration
class A
{
public:
void do_something(); // This is forward declaration
}
这篇关于C ++ #include guard的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!