C++ 包括什么?

C++ 包括什么?,c++,include,C++,Include,我了解a.h是否包括b.h,并且我不会在标题中声明b.h中的任何内容,仅包括a.h是良好做法。如果我要在标题中声明b.h中的任何内容,那么我应该同时包含a.h和b.h,以使标题自给自足 在我的标题中,我确实声明了A.h中的A类和B.h中的B类。然而,A类依赖于B类,所以我总是将它们一起使用。我从来不会独立于A类使用B类。在这种情况下,同时包括a.h和b.h还有意义吗 a.h #include "b.h" #include <queue> class A { private:

我了解
a.h
是否包括
b.h
,并且我不会在标题中声明
b.h
中的任何内容,仅包括
a.h
是良好做法。如果我要在标题中声明
b.h
中的任何内容,那么我应该同时包含
a.h
b.h
,以使标题自给自足

在我的标题中,我确实声明了
A.h
中的
A类
B.h
中的
B类
。然而,
A类
依赖于
B类
,所以我总是将它们一起使用。我从来不会独立于
A类使用
B类
。在这种情况下,同时包括
a.h
b.h
还有意义吗

a.h

#include "b.h"
#include <queue>

class A
{

private:
   std::queue<B> mFoo;
}
#包括“b.h”
#包括
甲级
{
私人:
std::队列mFoo;
}

在我的实际代码中,我认为当我只包含我的事件系统,而不是一些对我来说似乎多余的包含时,我的意图就更清楚了。

你应该始终包含直接依赖项:如果a直接依赖于bc,即使b已经包括ca也应该包括两者

明确说明您的依赖关系。您不应该依赖于其他模块已经依赖于您必须包含的模块这一事实。您永远不知道依赖关系树将来会发生什么变化

在这方面,具有隐式依赖关系会使代码变得脆弱


为了确保不通过包含两次来重新定义某个内容,可以将以下内容放入头文件中:

#ifndef GRANDFATHER_H
#define GRANDFATHER_H

struct foo {
    int member;
};

#endif /* GRANDFATHER_H */
你也可以使用

#pragma once
但并不是每个编译器都支持它


这样,即使预处理器会多次使用同一个include,它也不会重新包含代码。

我的规则:给定一些随机头
foo.h
,以下内容应该编译干净,最好也应该链接并运行:

#include "foo.h"
int main () {}
假设
foo.h
不包含任何语法错误(即,在您打算编译的上下文中包含它的源文件将被清除),但上面的代码仍然无法编译。这几乎总是意味着
foo.h
中缺少一些
#include
指令

这并没有告诉您是否真正需要
foo.h
中包含的所有标题。我有一个方便的小脚本来检查上面的内容。如果通过,它将创建一个
foo.h
的副本,并逐步注释掉
#include
指令,并查看
foo.h
的修改版本是否通过上述测试。任何通过的指令都表示可疑的多余指令
#include

问题是被认为是多余的
#include
指令可能不是多余的。假设
foo.h
定义了类
foo
,该类的数据成员类型为
Bar
Baz
(不是指针、成员)。标题
foo.h
正确地包括
bar.h
baz.h
,因为这两个类是在这里定义的。假设
bar.h
碰巧包括
baz.h
。作为
foo.h
的作者,我不在乎。我仍然应该在
foo.h
中包含这两个标题,因为
foo.h
直接依赖于这两个其他标题。在本例中,我的脚本将抱怨可疑的多余标题。这些抱怨是暗示,而不是命令


另一方面,修复
foo.h
,使我上面的简单测试程序编译干净是一项任务。

您不应该依赖间接包含。如果您需要
b.h
,则应将其包括在内。包括所有直接依赖项。不要包含依赖项所依赖的内容,除非它们也是您的直接依赖项。要清楚,通过在代码中声明某些内容,我将其作为依赖项?因此,不管我怎么想,我都应该把它包括进去。在我看来,如果
A类
需要
B类
并确保它被包括在内,你就不需要
B.h
以及
A.h
。我怀疑这与主流观点背道而驰。如果
类B
a.h
意外地包含,而不是“必然地”包含,那么它将是不同的。@user870130:除了其他人所说的,继续学习转发声明。如果您的代码使用B的原因是因为a使用了B,而随后a被修改为不使用B,使用B的代码将无法工作,除非您将其修改为也不使用B。所以,我不相信“你永远不知道依赖关系树在未来会如何变化”的论点。如果A使用B,那么它是直接依赖关系。如果它使用C,那么它也是直接依赖的。现在,即使B使用C,你仍然需要在A中包含C。这是因为B将来可能会发生变化:B:包含C好吧,有时候你可以通过前向声明逃脱。还有其他一些技巧。