C++ #在头文件或实现文件中导入

C++ #在头文件或实现文件中导入,c++,objective-c,c,coding-style,C++,Objective C,C,Coding Style,有些人有向头文件添加头文件导入/包含的习惯。另一方面,有些人在头文件中写入转发声明,并在实现文件中写入实际的#include或#import行 这方面有标准的做法吗?哪一个更好?为什么?当类具有浅层依赖关系时,需要包含前向引用而不是标头。例如: A.h #include "B.h" class A { B* pointer; }; #include "A.h" class B { A* pointer; }; class B; class A { B* pointer; }

有些人有向头文件添加头文件导入/包含的习惯。另一方面,有些人在头文件中写入转发声明,并在实现文件中写入实际的#include或#import行


这方面有标准的做法吗?哪一个更好?为什么?

当类具有浅层依赖关系时,需要包含前向引用而不是标头。例如:

A.h

#include "B.h"
class A {
   B* pointer;
};
#include "A.h"
class B {
   A* pointer;
};
class B;
class A {
   B* pointer;
};
class A;
class B {
   A* pointer;
};
B.h

#include "B.h"
class A {
   B* pointer;
};
#include "A.h"
class B {
   A* pointer;
};
class B;
class A {
   B* pointer;
};
class A;
class B {
   A* pointer;
};
将在编译时中断

A.h

#include "B.h"
class A {
   B* pointer;
};
#include "A.h"
class B {
   A* pointer;
};
class B;
class A {
   B* pointer;
};
class A;
class B {
   A* pointer;
};
B.h

#include "B.h"
class A {
   B* pointer;
};
#include "A.h"
class B {
   A* pointer;
};
class B;
class A {
   B* pointer;
};
class A;
class B {
   A* pointer;
};

将起作用,因为每个类只需要知道声明中存在另一个类。

我将导入写入头文件,以便每个实现文件只有一个包含指令。这还具有对模块代码的用户隐藏依赖项的优点

然而,同样的隐藏也有一个缺点:模块的用户可能正在导入头中包含的所有类型的其他头,而他可能根本不需要这些头。从这个角度来看,最好在实现文件中包含inclusion指令,即使这意味着手动解析依赖项,因为这会导致代码更轻

我认为没有一个答案。考虑到我给出的原因,我更喜欢第一种方法,我认为它会导致更干净的代码(尽管更重,并且可能有不必要的导入)

我不记得我引用的是谁的话(因此这个短语并不准确),但我总是记得读过:“程序是为人类阅读而编写的,局部是为计算机执行而编写的”。我并不特别关心我的模块的用户是否需要几千字节的代码,只要他能够干净、轻松地导入代码并使用单个指令即可

再说,我认为这是一个味觉的问题,除非我没有考虑到什么。在这种情况下,欢迎发表评论


干杯。

给定X.h和X.c,如果您
#包含X.h中的所有内容,那么
#包含
的“X”客户端也将包含所有这些标题,即使某些标题可能只在X.c中需要

X.h应该只包含解析X.h所需的内容。它应该假设翻译单元不会包含其他标题,以确保重新排序的包含内容不会破坏客户端。X.c应包括实施所需的任何额外费用


这将最小化重新编译依赖项。您不希望只对实现进行更改以影响标头,从而触发客户端重新编译。您只需直接从X.c.中包含即可。

在现实世界中具有这样的循环依赖关系是一种好的设计/体系结构吗?不,不是,应该尽可能避免。如果不可避免,并且两个模块需要相互包含,那么在99%的情况下,它们在语义上是一个相同的模块,或者可以是两者都依赖的组合基本模块的超级模块。更好的做法是为a和B提供前向声明头,分别只包含“类a”和“类B”,和都包含在A.h和B.h中。这样,当从A构建任何东西(包括它的测试用例)时,A的正向声明、声明和实现自然会相互引用,因此从类A更改为某些模板和类型定义不会让B对编译器撒谎。@Santiago:是的,软件模块中的循环依赖通常是不好的做法。但在个别类别中,循环引用在许多情况下既常见又必要。在我看来,父指针通常创建循环引用。实际上,我根本不提倡使用它们,只是解释了必须使用前向声明的情况。我不明白你为什么要投反对票。对不起,但你的逻辑混乱了,你的偏好与公认的最佳实践背道而驰。第1段:“这还具有向模块代码的用户隐藏依赖项的优点。”/“只要用户能够干净、轻松地导入依赖项并将其与单个指令一起使用”。您应该包括解析头所需的内容,客户端无论如何都不必包括实现所需的任何其他头来使用该功能。(不管是哪种方式,客户端仍然必须添加对象/库上的链接器依赖项。)老实说,我看不出我的逻辑有多混乱。将文件添加到编译行与强制某人在代码中导入几个模块不同。然而,我看到的是你是多么的不尊重,所以请不要再评论了。我将亲自看一看有关这方面的文章,并下定决心。