包括什么

What to #include?

本文关键字:什么 包括      更新时间:2023-10-16

我知道如果a.h包括b.h,我不声明任何从b.h在我的头只包括a.h是很好的做法。如果我要在我的头文件中声明b.h中的任何内容,那么我应该包括a.hb.h以使我的头文件自给自足。

在我的头我声明class Aa.hclass Bb.h。然而,class A依赖于class B,所以我总是把它们放在一起使用。我从不单独使用class Bclass A。在这种情况下,它仍然有意义,包括a.hb.h ?

a.h

#include "b.h"
#include <queue>
class A
{
private:
   std::queue<B> mFoo;
}

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

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

明确你的依赖关系。您不应该依赖于其他模块已经依赖于您必须包含的模块的事实。你永远不知道依赖树将来会如何变化。

在这方面,隐式依赖会使你的代码脆弱。


为了确保你不会通过包含两次来重新定义某个内容,你可以在头文件中添加header guard:

#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,该类的数据成员类型分别为BarBaz(不是指针,是成员)。头foo.h正确地包括bar.hbaz.h,因为这是定义这两个类的地方。假设bar.h碰巧包含baz.h。作为foo.h的作者,我不在乎。我仍然应该包括这两个头在foo.h,因为foo.h有直接依赖于这两个其他的头。在这种情况下,我的脚本将抱怨可疑的多余头。这些抱怨是暗示,不是命令。

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