C++ 在任何情况下,是否有必要或有用;“双链接”;头文件?(C+;+;)

C++ 在任何情况下,是否有必要或有用;“双链接”;头文件?(C+;+;),c++,include,header,infinity,C++,Include,Header,Infinity,我使用术语“双链接”是因为我不知道实际的短语是什么,或者是否有,但假设您有两个标题,head1.h和head2.h,其中包含以下内容: 在标题1.h中: #include"head2.h" //do stuff 在标题2.h中: #include"head1.h" //do stuff 我把它想象成两个相对放置的镜子,因为它不是一个真正的无限循环,而是将无限引入有限计算机的另一种形式(但我离题了)。问题是,在任何情况下,使用这个概念或这个概念的变体是有用的还是必要的?(即:我想goto可以用

我使用术语“双链接”是因为我不知道实际的短语是什么,或者是否有,但假设您有两个标题,head1.h和head2.h,其中包含以下内容:

在标题1.h中:

#include"head2.h"
//do stuff
在标题2.h中:

#include"head1.h"
//do stuff
我把它想象成两个相对放置的镜子,因为它不是一个真正的无限循环,而是将无限引入有限计算机的另一种形式(但我离题了)。问题是,在任何情况下,使用这个概念或这个概念的变体是有用的还是必要的?(即:我想goto可以用作即兴休息)。

这是一个“循环包含”,不,这不是一个理想的做法。您的goto没有帮助,因为goto是程序执行的一部分,而#include在编译的预处理阶段被解释

通常的做法是使头文件具有如下结构

#ifndef FOO_H
#define FOO_H
... rest of the include file here
#endif
所以他们不会试图两次定义相同的东西

如果您尝试一下,会发生以下情况:

文件中的bash$gcc crecursive.c
包括在bh.h:1中

。。。省略了许多行

猛击$

这是一个“循环包含”,不,这不是一个理想的做法。您的goto没有帮助,因为goto是程序执行的一部分,而#include在编译的预处理阶段被解释

通常的做法是使头文件具有如下结构

#ifndef FOO_H
#define FOO_H
... rest of the include file here
#endif
所以他们不会试图两次定义相同的东西

如果您尝试一下,会发生以下情况:

文件中的bash$gcc crecursive.c
包括在bh.h:1中

。。。省略了许多行

猛击$


通常,标头具有预处理器语句,以精确防止此类事件导致无限递归:

#ifndef MY_FILE_H
#define MY_FILE_H

//do stuff

#endif

即使有了这种保护,相互包含通常也是一个坏主意。

通常,标头具有预处理器语句,以精确地防止这种情况导致无限递归:

#ifndef MY_FILE_H
#define MY_FILE_H

//do stuff

#endif

即使有了这种保护,相互包含通常也是个坏主意。

避免这种情况的通常方法是使用空类声明

//head1.h

class Foo;

class Bar {
public:
   Bar(Foo* f) : foo(f) {}
private:
   Foo* foo;
};

// head2.h

class Bar;

class Foo {
public:
    void func(Bar* bar); 
};
当一个头文件创建了许多需要先声明的类时,您通常会得到一个包含文件,如

//fwd.h

class Bar;
class Foo;

// head1.h

#include "fwd.h"

class Foo { ....

// head2.h

#include "fwd.h"

class Bar { ....

避免这种情况的通常方法是使用空类声明

//head1.h

class Foo;

class Bar {
public:
   Bar(Foo* f) : foo(f) {}
private:
   Foo* foo;
};

// head2.h

class Bar;

class Foo {
public:
    void func(Bar* bar); 
};
当一个头文件创建了许多需要先声明的类时,您通常会得到一个包含文件,如

//fwd.h

class Bar;
class Foo;

// head1.h

#include "fwd.h"

class Foo { ....

// head2.h

#include "fwd.h"

class Bar { ....
我把它想象成两个米罗 彼此对立,因为这不是真的 无限循环

你想错了 请记住#include只不过是复制/粘贴,它发生在编译程序之前。因此,您在编译过程中设置了一个无限循环。编译器读取head1.h,它以#include“head2.h”开头。所以它插入head2.h并继续解析它,但它以#include“head1.h”开头,所以我们必须包含它,以此类推

您通常具有include防护,以防止将编译器放入无限循环

关键是,这是在编译程序之前的纯文本处理,当然是在执行程序之前,所以它不是真正可以用于任何建设性的东西,除非复制/粘贴无限次是您的乐趣所在

我把它想象成两个米罗 彼此对立,因为这不是真的 无限循环

你想错了 请记住#include只不过是复制/粘贴,它发生在编译程序之前。因此,您在编译过程中设置了一个无限循环。编译器读取head1.h,它以#include“head2.h”开头。所以它插入head2.h并继续解析它,但它以#include“head1.h”开头,所以我们必须包含它,以此类推

您通常具有include防护,以防止将编译器放入无限循环


关键是,这是在编译程序之前的纯文本处理,当然是在执行程序之前,所以它不是真正可以用于任何建设性的东西,除非复制/粘贴无限次是您的乐趣所在

“空类”声明实际上称为前向声明FYI“空类”声明实际上称为前向声明FYIOTOH,一个小的变化是常见的-head1.h包括head3.h(因为它需要head3.h的服务),head2.h也是如此,而同时包含head1.h和head2.h的代码需要两次防止包含head3.h。图中所示的收割台防护装置可防止其引起故障。OTOH,一个微小的变化是常见的-head1.h包括head3.h(因为它需要head3.h的服务),head2.h也是如此,同时包括head1.h和head2.h的代码需要两次保护,以防包含head3.h。所示的收割台护罩可防止造成故障。