包含来自包含文件的最佳做法

时间:2013-05-16 07:55:54

标签: c++

我想知道是否有一些pro和contra在include文件中直接包含include语句,而不是在源文件中包含它们。

我个人喜欢让我的包含“干净”所以,当我将它们包含在某个c / cpp文件中时,我不必追捕所有可能的标题,因为包含文件本身不会处理它。另一方面,如果我在include文件中包含include,则编译时间可能会变大,因为即使使用include guard,也必须首先解析文件。这只是一个品味问题,还是有其他优点/缺点?

我的意思是:

sample.h

#ifdef ...

#include "my_needed_file.h"
#include ...

class myclass
{
}

#endif

sample.c文件

#include "sample.h"

my code goes here

对战:

sample.h

#ifdef ...

class myclass
{
}

#endif

sample.c文件

#include "my_needed_file.h"
#include ...
#include "sample.h"

my code goes here

6 个答案:

答案 0 :(得分:7)

实际上没有任何标准的最佳做法,但对于大多数帐户,您应该在标题中包含您真正所需的内容,并向前宣告您的内容。

如果实现文件需要显式标头不需要的内容,那么该实现文件应该包含它本身。

答案 1 :(得分:3)

语言没有要求,但几乎普遍 接受的编码规则是所有标题必须是自己的 足够;源文件,由单个语句组成 包括include应该编译没有错误。通常 验证这一点的方法是包含实现文件 它之前的标题。

编译器只需要读取每个包含一次。 如果它 可以肯定地确定它已经读过文件, 并且在阅读时,它会检测包含保护模式 无需重读文件;它只是检查是否控制 预处理器令牌(仍)定义。 (有 编译器无法检测的配置 包含的文件是否与之前包含的文件相同 文件。在这种情况下,它必须再次读取文件,并且 重新解析它。然而,这种情况相当罕见。)

答案 2 :(得分:2)

头文件应该被视为API。让我们假设您正在为客户端编写库,您将为它们提供一个头文件,用于包含在他们的代码中,以及一个用于链接的已编译二进制库。

在这种情况下,在头文件中添加'#include'指令会给您的客户端和您带来很多问题,因为现在您必须提供不必要的头文件才能进行编译。尽可能向前声明可以实现更清晰的API。它还使您的客户端可以根据需要在标题上实现自己的功能。

如果您确定您的标题永远不会在当前项目之外使用,那么任何一种方式都不是问题。如果您使用的是包含保护,编译时间也不是问题,您应该一直使用它。

答案 3 :(得分:1)

标题中包含更多(不需要的)包含意味着在界面级别可以看到更多(不需要的)符号。这可能会造成很多破坏,可能导致符号冲突和臃肿的界面

答案 4 :(得分:1)

  

另一方面,如果我在include文件中包含include,编译时间可能会变大,因为即使使用include guard也是如此

如果您的编译器不记得哪些文件包含防护并且避免重新打开并重新标记文件,那么可以获得更好的编译器。大多数现代编译器已经这样做多年了,因此多次包含同一文件是没有成本的(只要它包含防护)。参见例如http://gcc.gnu.org/onlinedocs/cpp/Once_002dOnly-Headers.html

标题应该是自给自足的并包含/声明他们需要的东西。期望标题的用户包含其依赖项是不好的做法,也是让用户讨厌你的好方法。

如果在 my_needed_file.h之前需要sample.h(因为sample.h需要声明/定义),那么它应该包含在sample.h中,没有问题。如果sample.h中只需要 ,而sample.c只需要 ,那么只需将其包含在那里,我的偏好是在之后将其包含在中> sample.h,如果sample.h 缺少所需的标题,那么您很快就会知道它:

// sample.c
#include "sample.h"
#include "my_needed_file.h"
#include ...
#include <std_header>
// ...

如果您使用此#include订单,则会强制您sample.h自给自足,这可确保您不会对标题的其他用户造成问题和烦恼。

答案 5 :(得分:-1)

我认为仅仅因为以下原因,第二种方法更好。

  1. 当您的头文件中有一个功能模板时。

    class myclass
    {
        template<class T>
        void method(T& a)
        {
           ...
        }
    }
    
  2. 并且您不希望在myclass.cxx的源文件中使用它。但是你想在xyz.cxx中使用它,如果你采用第一种方法,那么你最终会包含myclass.cxx所需的所有文件,这对xyz.cxx没用。

    这就是我现在想到的所有差异。所以我想说应该采用第二种方法,因为它会使你的代码在将来保持不变。