C ++ #include guard [英] C++ #include guards

查看:156
本文介绍了C ++ #include guard的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

已解决



真正帮助我的是,我可以在.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 #includes 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 #included 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 #includes. 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 #includes 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆