C++ 在任何情况下,是否有必要或有用;“双链接”;头文件?(C+;+;)
我使用术语“双链接”是因为我不知道实际的短语是什么,或者是否有,但假设您有两个标题,head1.h和head2.h,其中包含以下内容: 在标题1.h中: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可以用
#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。所示的收割台护罩可防止造成故障。