可能重复:
在 C++ 中应该将“包含”放在哪里
#include
显然,关于是否将指令放入 C++ 头文件(或者,作为替代方案,#include
仅放入 cpp 文件),有两种“思想流派” 。有人说没问题,有人说只会出问题。有谁知道这个讨论是否已经得出结论什么是首选?
可能重复:
在 C++ 中应该将“包含”放在哪里
#include
显然,关于是否将指令放入 C++ 头文件(或者,作为替代方案,#include
仅放入 cpp 文件),有两种“思想流派” 。有人说没问题,有人说只会出问题。有谁知道这个讨论是否已经得出结论什么是首选?
我不知道任何关于此的思想流派。当需要它们时将它们放在标题中,否则转发声明并将它们放在.cpp
需要它们的文件中。在不需要的地方包含标题没有任何好处。
我发现有效的是遵循一些简单的规则:
获得第一点是相当容易的:首先从实现它声明的源代码中包含标题。但是,将第二点完全正确并非易事,而且我认为它需要工具支持才能完全正确。但是,一些不必要的依赖项通常并没有那么糟糕。
根据经验,只要需要对它们进行完整定义,就不会在标题中包含标题。大多数情况下,您在头文件中使用类的指针,因此在此处转发声明它们就可以了。
我认为这个问题很久以前就解决了:标题应该是自包含的(这不应该依赖于用户之前包含其他标题 - 这方面已经解决了很长时间,以至于有些人甚至不知道有对此进行了辩论,但您的put 仅包含在 .cpp 中似乎暗示了这一点)但很少(即,当声明足以实现自包含时,不应包含定义)。
自包含的原因是维护:如果一个头被修改并且现在依赖于新的东西,你必须跟踪它用于包含新依赖的所有地方。顺便说一句,确保自包含的标准技巧是在 .cpp 中首先包含为 .cpp 中定义的事物提供声明的标头。
这些与其说是宗教学派,不如说是学派。实际上,这两种方法都有其优点和缺点,并且要使任何一种方法成功,都需要遵循某些实践。但是这些方法中只有一种会“扩展到”大型项目。
在标头中不包含标头的优点是编译速度更快。然而,这种优势并不来自只读取一次的标头,因为即使您在标头中包含标头,智能编译器也可以解决这个问题。速度优势来自于您只包含给定源文件严格必需的那些标头。另一个优点是,如果我们查看源文件,我们可以准确地看到它的依赖项是什么:头文件的平面列表清楚地向我们提供了这一点。
然而,这种做法很难维持,尤其是在有很多程序员的大型项目中。当您想使用 module 时,这很不方便foo
,但您不能只是#include "foo.h"
:您需要包含 35 个其他标头。
最终发生的事情是这样的:程序员不会浪费时间去发现他们只需要添加模块的确切的、最小的标题集foo
。为了节省时间,他们将转到一些与他们正在处理的源文件类似的示例源文件,然后剪切并粘贴所有#include
指令。然后他们将尝试编译它,如果它没有构建,那么他们将从#include
其他地方剪切并粘贴更多指令,并重复此操作直到它工作。
最终结果是,您会一点一点地失去编译速度更快的优势,因为您的文件现在包含不必要的头文件。此外,#include
指令列表不再显示真正的依赖关系。此外,当您现在进行增量编译时,由于这些错误的依赖关系,您编译的内容超出了必要的范围。
一旦每个源文件都包含几乎每个头文件,您还不如拥有一个everything.h
包含所有头文件的大文件,然后#include "everything.h"
在每个源文件中。
因此,这种仅包含特定标头的做法最好留给由少数开发人员仔细维护的小型项目,这些开发人员有足够的时间手动维护最小包含依赖项的道德,或者编写工具来寻找不必要的#include
指令。