C++“额外”头文件

3
问题是关于包含一个不必要的头文件以避免在子文件中多次调用它。 情景如下,我有几个文件:
srlogger.h

srinterface.h

srinterface.cc
#include <srinterface.h>
#include "srlogger.h"

srbinhttp.h
#include "srinterface.h"

srbinhttp.cc
#include <srbinhttp.h>
#include "srlogger.h"

srsocket.h
#include "srinterface.h"

srsocket.cc
#include <srsocket.h>
#include "srlogger.h"

srhttp.h
#include "srinterface.h"

srhttp.cc
#include <srhttp.h>
#include "srlogger.h"

现在,我想要做的是从所有显示的.cc文件中删除#include "srlogger.h",并将其改为在srinterface.h文件中包含它:
srinterface.h
#include "srlogger.h"

由于所有的.cc相关头文件都包含了srinterface.h,因此srlogger.h也会被覆盖。那么,这样做为什么不好呢?
请不要只说您应该只包括编译所需的必要头文件,而不包括任何额外的内容,这并不足够解释。
我想知道在实际例子中为什么这样做是不好的。
如果有人从srinterface.h中删除#include "srlogger.h",它将破坏其他文件,这是一个薄弱的解释。在include之后添加注释可以轻松警告其他人。
最让我感兴趣的是它是否会对编译产生不良影响,对象或可执行文件的大小是否会因此改变,它是否会影响性能。
或者你有一个非常好的解释为什么这样做不好。
PS:如果你好奇为什么我要这样做,是因为我正在映射文件之间的依赖关系,这样做我可以创建一个图形化可视化工具来展示所有依赖关系,更容易理解各个部分如何相互配合。将子头文件转移到高层次头文件中的公共头文件可以在所有文件之间创建更有组织的结构。

1
这并没有回答问题,但是对于系统头文件使用#include <...>,对于自己的头文件使用#include "..." - Pete Becker
@Pete Becker - 我不反对,但你应该解释一下为什么。此外,如果您告诉编译器您自己的包含目录,则使用“<>”也可以。无论如何,您的评论并没有解释这两种形式之间的区别,而只是说“这样做”,这并不像它本来可以那样有帮助。 - Jesper Juhl
1
@JesperJuhl -- 如果那是一个答案,我会同意。但它不是,既然它没有意图回答问题,它很短,并且不打算引发讨论。 - Pete Becker
@Pete Becker - 好的,可以接受 :-) - Jesper Juhl
2个回答

3
潜在的负面影响之一是编译时间。如果有人包含了你的头文件,却不需要它所依赖的头文件,那么该编译单元的编译时间将因无必要的原因而增加。
对于玩具项目或小型项目(几百个文件),其编译时间只需几秒钟,这没有什么实质性的差别。但当你处理跨越数以百万计行的代码和数十万个文件的项目,已经需要显著部分小时来编译时,如果你添加一个被其他12000个文件包含的头文件引用,因为你懒得明确地将它添加到实际需要它的120个文件中(但恰好包含了公共头文件) - 那么你就不会受欢迎,因为你刚刚将每个人的平均构建时间增加了几分钟。
在糟糕的代码库中还存在一个风险,即您(不必要地)将头文件拖入其他文件中可能重新定义了破坏了最初根本不需要另一个头文件的源文件。
出于上述原因,我认为头文件应该只包含它们自己真正需要的内容,并且不能前向声明。实现文件应该只包含它们真正需要的头文件(并首先包含它们自己的头文件,以确保它们是自包含的)。
希望这回答了您的问题。

1
我理解你的观点,很有道理,谢谢。我还做了更多的研究,我想由于这个原因,目标文件和程序会增加。我发现这个视频很有用,展示了编译和链接的过程,不过要跳到中间部分: https://www.youtube.com/watch?v=5UMHbzZGQuE&index=17&list=PLggLP4f-rq02gmlePH-vQJ8PF6hyf08CN - Daniel

1
"这个问题是关于在子文件中多次调用同一个头文件的解决方法,而加入不必要的头文件会导致这种情况的出现。"
"使用 include guards 可以解决在同一文件中包含多个头文件的可行性问题,它可以在一定程度上减少不必要的头文件引入。请参考以下链接:"
"C++ #include guards"
"在你的头文件中添加以下内容即可创建 include guard:"
//at the very top of the header
#ifndef NAMEOFHEADER_H
#define NAMEOFHEADER_H

// header info

//at the very last line of the header
#endif

这样做可以避免在另一个.h或.cpp文件中多次累积相同的头文件。
正如下面的评论所述,即使每个头文件都有包含卫士,您仍然可能会在编译器的预处理器指令期间定义甚至不需要的文件信息。这在跨多个文件的包含链中必定会发生。

1
当头文件被包含在10000个文件中,但你添加到头文件的额外包含只有10个文件需要时,包含保护并不能帮助你。现在所有的10000个源文件都需要支付编译额外头文件的成本(这将累积为真实时间-分钟)——对于大型代码库来说速度很快。 - Jesper Juhl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接