组织包括

Organize includes

本文关键字:包括      更新时间:2023-10-16
  • 是否有一些首选的组织方式包括指令
  • 将您需要的文件包括在.cpp文件中而不是.h文件中更好吗?翻译单位是否受到某种影响
  • 如果我在.h文件和.cpp文件中都需要它,我应该把它包括在.h文件中吗?这有关系吗
  • 将已经定义的文件保存在预编译头(stdafx.h)中(例如std和第三方库)是一种好的做法吗?我自己的文件怎么样?在创建它们的过程中,我应该将它们包含在stdafx.h文件中吗

// myClass.h
#include <string>
// ^-------- should I include it here? --------
class myClass{
    myClass();
    ~myClass();
    int calculation()
};
// myClass.cpp
#include "myClass.h"
#include <string>
//  ^-------- or maybe here?  --------
[..]
int myClass::calculation(){
    std::string someString = "Hello World";
    return someString.length();
}

// stdafx.h
#include <string.h>
// ^--------- or perhaps here, and then include stdafx.h everywhere? -------
  1. 你应该把它们放在文件的顶部,放在一个地方。这是每个人所期望的。此外,对它们进行分组也很有用,例如,首先是所有标准标头,然后是第三方标头(按库分组),然后是您自己的标头。在整个项目中保持此顺序的一致性。它使理解依赖关系变得更加容易。正如@James Kanze所指出的,将声明内容的头放在第一位也很有用。通过这种方式,您可以确保它在首先包含时工作(这意味着它不依赖于任何不包含它自己的包含)
  2. 保持范围尽可能小,这样头中的更改影响的翻译单位数量就最少。这意味着,只要可能,只将其包含在cpp-文件中。正如@Pedro d'Aquino所评论的,您可以通过尽可能使用前向声明来减少标头中的include数量(基本上只要您只使用对给定类型的引用或指针)
  3. 两者都显式比隐式好
  4. 经过一番阅读,我认为只有当你确信标题不再更改时,你才应该在PCH中包含标题。这适用于所有标准头以及(可能)第三方库。对于你自己的图书馆,你是评判者

这篇关于头文件包含模式的文章应该对您有所帮助。

  • 是否有一些首选的组织方式包括指令

,您可以在上面的文章中找到它们。

  • 将需要的文件包括在.cpp文件中而不是.h文件?翻译单位是不知怎么受到了影响

,最好将它们放在.cpp中。即使在定义另一个类型时需要一个已定义的类型,也可以使用正向声明。

  • 如果我在.h文件和.cpp文件中都需要它,我应该只是否将其包含在.h文件中?会吗重要吗

仅在.h文件中,但建议在头文件中转发声明,并包含在.cpp文件中。

  • 将已定义的文件保存在预编译文件中是一种好的做法吗标头(stdafx.h),例如std和第三方图书馆?怎么样我自己的文件,我应该把它们包括在内吗一个stdafx.h文件创建它们

我个人没有使用预编译的头文件,但之前在Stackoverflow上已经讨论过它们:

预编译标头?我们真的需要它们吗

是否有一些首选的组织方式包括指令?

没有共同的约定。有些人建议用字母排序,我个人不喜欢,更喜欢按逻辑分组。

将需要的文件包括在.cpp文件中而不是.h文件中更好吗?

总的来说,是的。它减少了编译器打开和读取头文件以查看包含保护的次数。这可能会减少总体编译时间。出于同样的原因,有时还建议在头中转发声明尽可能多的类,并实际上只将它们包含在.cpp中。例如,"Qt人"就是这样做的。

翻译单位是否受到某种影响?

在语义意义上,没有。

如果我在.h文件和.cpp文件中都需要它,我应该把它包括在.h文件中吗?这有关系吗?

只需将其包含在标题中即可。

将已经定义的文件保存在预编译头(stdafx.h)中(例如std和第三方库)是否是一种好的做法?我自己的文件怎么样?在创建它们的过程中,我是否应该将它们包含在stdafx.h文件中?

预编译的标头可以显著减少编译时间。例如:我的一个项目,包括boost::spirit::qi,在PCH打开的情况下,编译时间为20秒,在没有PCH的情况下编译时间为80秒。一般来说,如果您使用一些像boost这样的大量填充模板的库,您会希望利用PCH的优势。

至于代码示例中的问题:由于头中没有使用std::string,因此最好将其包含在.cpp文件中。stdafx.h中的#include <string>也可以,但这只会给您的项目增加一点复杂性,您几乎不会注意到任何编译加速。

(4)我不建议在stdafx.h或类似的"include_first.h"文件中包含任何其他文件。直接包含到cpp或特定的h文件中,可以显式地表达代码的依赖关系,并排除多余的依赖关系。当您决定将单片代码分解为几个库或dll时,它尤其有用。就我个人而言,我使用像"include_first.h"(stdafx.h)这样的文件仅用于配置目的(该文件仅包含当前应用程序配置的宏定义)
通过标记另一个文件而不是stdafx.h来停止预编译,可以为自己的文件提供预编译头(例如,可以使用名为"stop_pch.h"的特殊空文件)。
注意,对于预处理器的某些特定用途(特别是BOOST_PP_*中使用的某些技术),预编译的标头可能无法正常工作。

从性能角度来看:

更改stdafx.h中包含的任何头都将触发新的预编译,因此这取决于代码的"冻结"程度。外部库是stdafx.h包含的典型候选库,但您当然也可以包含自己的库-这是一种基于更改频率的折衷。

此外,使用Microsoft编译器,您可以将其放在每个头文件的顶部:

#pragma once

这允许编译器在第一次出现后完全跳过该文件,从而保存I/O操作。传统的ifndef/define/endif模式需要在每次包含文件时打开并解析该文件,这当然需要一些时间。它肯定会积累并变得引人注目!

(为了可移植性,请确保保留传统的保护。)

注意翻译单元中的类顺序需要正确,或者某些c++功能被禁用,从而导致编译时错误,这一点可能很重要。

编辑:添加示例:

class A { };
class B { A a; }; // order of classes need to be correct