Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么要将整个标题内容放在保护令牌中? C和C++在声明之间定义了一个定义。_C++_C_Header_Header Files_Include Guards - Fatal编程技术网

为什么要将整个标题内容放在保护令牌中? C和C++在声明之间定义了一个定义。

为什么要将整个标题内容放在保护令牌中? C和C++在声明之间定义了一个定义。,c++,c,header,header-files,include-guards,C++,C,Header,Header Files,Include Guards,可以多次声明符号,但只允许定义一次。通过了解这一点,我有了一个想法,即将声明放在防护装置之外,而将定义放在防护装置内部: // declarations int foo(int x, int y); int bar(int x, int y); extern double something; class X; #ifndef _MY_HEADER_H_ #define _MY_HEADER_H_ #include "otherheader1.h" #include "otherhea

可以多次声明符号,但只允许定义一次。通过了解这一点,我有了一个想法,即将声明放在防护装置之外,而将定义放在防护装置内部:

// declarations

int foo(int x, int y);
int bar(int x, int y);

extern double something;

class X;

#ifndef _MY_HEADER_H_
#define _MY_HEADER_H_

#include "otherheader1.h"
#include "otherheader2.h"

// definitions of structures, classes.

class X
{
    // blah blah...
};

#endif
通过这种方式,我可以按照我想要的顺序包含标题。循环依赖可能不会成为问题

那么,如果我们可以将声明放在外部,为什么要用保护令牌保护整个头部呢

我的理由如下:

当两个标题以某种方式相互引用时,您可能经常遇到问题。通常会出现未声明的符号错误,第一个反射是包含必要的标题。但是,当两个标题碰巧包含彼此时,就会出现隐藏的错误

a、 h:

b、 h

当在b.cpp中包含b.h时,在a.h中会出现一个错误,即未声明b,但包含头。(这是wtf的时刻。)

这是因为头部防护装置不会嵌套:

#ifndef B_H
#define B_H

#ifndef A_H
#define A_H

// B_H already defined no include here.

class A {B *b;}       

#endif

class B {A *a;}       

#endif
如果将声明置于防护之外,则可以防止:

class B; // in b.h

#ifndef B_H
#define B_H

class A; // in a.h

#ifndef A_H
#define A_H

class B; // again from b.h
// B_H already defined no include here, no redefinition.

class A {B *b;}       

#endif

class B {A *a;}       

#endif
没问题


更新:将标题包含放入保护中(很抱歉,这是一个错误)。

如果严格来说它是一个标题保护,则没有必要-如果包含多个标题,则声明已经可见


反对这种做法的另一个原因是,在严格的头保护之外的声明可能会禁用编译器对多重包含头的优化(也就是说,它将多次打开头)。

因为它允许您多次包含头,而不必担心冲突


虽然只有一个嵌套级别是不必要的,但如果有多个嵌套级别(考虑包括h1,然后包括h2,其中包括h1,因为它需要h1)。

系统无法防止循环包含。例如:

标题A:

#include "B.h"
#ifndef A_H_INCLUDED
#define A_H_INCLUDED
// ...
#endif // A_H_INCLUDED
标题B:

#include "A.h"
#ifndef B_H_INCLUDED
#define B_H_INCLUDED
// ...
#endif // B_H_INCLUDED
源文件:

#include "A.h" // includes B, which includes A, which includes B, ...

当你只考虑“声明”时,你错过了一半的故事。C++还具有“类定义”的概念,它是一种第三种新型动物——它既是类的定义,也是成员函数的声明。 由于类的定义不能超过一次(就像任何定义一样),所以不能超过一次包含带有类定义的头文件

现在假设您在
Foo.hpp
中有一些实用程序类
Foo
,并且您有两个独立的模块
a.hpp
b.hpp
,它们都需要
Foo
。您的主程序必须包含
a.hpp
b.hpp
,但现在您尝试两次包含
foo.hpp
,从而包含
foo
的类定义


输入includeguards.

一个简单的答案就是编译速度。编译器,如GCC和其他可能的编译器,可以检测到完整的文件头保护,并避免在多次遇到这些文件时读取和重新处理这些文件。如果您不将整个文件包装在头保护中,那么很有可能每次遇到头时都会迫使编译器重新计算它。

好吧,为什么不呢?为什么要投入精力去思考头球后卫能做什么,不能做什么?您的方法的好处在哪里?大多数教师和专业人士都不鼓励在单个文件中实现类。@harold:并为不支持它的编译器在其周围添加
\ifdefs
。@v01d我不是在头中实现类,只是定义成员方法名称等,当然,实现要用到cpp文件。这是真的,但是通过仔细设计可以避免循环包含。在一个完全分离的头/实现设计中,永远不会有真正的需要,甚至自然的情况下,循环包含应该发生。“我把定义放在警卫里面,而把声明放在警卫外面。”@Calmarius:听起来像是维护和可读性的噩梦。为什么要做这样一件费劲乏味的事情?为什么要在这上面浪费时间呢?你强迫自己做的决定越少,犯错误的机会就越少。它如何做到这一点而不首先扫描文件?@Calmarius第一次包含文件时,编译器会读取它并记录它是否有完整的文件include guard(或pragma one)然后知道它不必在翻译单元的其余部分再次阅读它。
#include "A.h"
#ifndef B_H_INCLUDED
#define B_H_INCLUDED
// ...
#endif // B_H_INCLUDED
#include "A.h" // includes B, which includes A, which includes B, ...