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直接依赖于b和c,即使b已经包括c,a也应该包括两者
明确说明您的依赖关系。您不应该依赖于其他模块已经依赖于您必须包含的模块这一事实。您永远不知道依赖关系树将来会发生什么变化
在这方面,具有隐式依赖关系会使代码变得脆弱
为了确保不通过包含两次来重新定义某个内容,可以将以下内容放入头文件中:
#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好吧,有时候你可以通过前向声明逃脱。还有其他一些技巧。