在头文件/cpp 文件中应该以什么顺序声明头文件?显然,后续标头所需的标头应该更早,并且特定于类的标头应该位于 cpp 范围而不是标头范围中,但是是否有设定的顺序约定/最佳实践?

有帮助吗?

解决方案

在头文件中,您必须包含所有头文件才能使其可编译。并且不要忘记使用前向声明而不是某些标头。

在源文件中:

  • 对应的头文件
  • 必要的项目标题
  • 3rd 方库标头
  • 标准库头文件
  • 系统头文件

按照这个顺序,您将不会错过任何忘记包含自己的库的头文件。

其他提示

良好做法:每个.h文件都应该有一个.cpp,首先包含.hpp。这证明任何.h文件都可以放在第一位。

即使标头不需要实现,也可以创建一个仅包含该.h文件的.cpp,而不是其他内容。

这意味着您可以按照自己喜欢的方式回答问题。你把它们包含在哪个顺序并不重要。

有关更多精彩提示,请尝试以下书籍:大型C ++软件设计 - 遗憾的是它太贵了,但实际上它是C ++源代码布局的生存指南。

在头文件中,我倾向于首先放置标准头,然后是我自己的头(两个列表按字母顺序排序)。在实现文件中,我首先将标题对应(如果有的话),然后是标准标题和其他依赖标题。

顺序不重要,除非您充分利用宏和#define;在这种情况下,您必须检查您定义的宏是否不替换之前包含的宏(当然,除非您想要的是这样)。

关于本声明

  

后续标题所需的那些应该更早

标题不应该依赖于之前包含的其他标题!如果它需要标题,它只包括它们。标题保护将阻止多重包含:

#ifndef FOO_HEADER_H
#define FOO_HEADER_H
...
#endif

修改

由于我写了这个答案,我改变了在代码中对include指令进行排序的方法。现在,我尝试始终按标准化的顺序添加标题,因此我的项目的标题首先出现,然后是第三方库标题,然后是标准标题。

例如,如果我的某个文件使用了我编写的库,Qt,Boost和标准库,我将按以下顺序订购包含:

//foo.cpp
#include "foo.hpp"

#include <my_library.hpp>
// other headers related to my_library

#include <QtCore/qalgorithms.h>
// other Qt headers

#include <boost/format.hpp> // Boost is arguably more standard than Qt
// other boost headers

#include <algorithms>
// other standard algorithms

我这样做的原因是在我自己的标题中检测缺少的依赖项:例如,假设my_library.hpp使用std::copy,但不包括<algorithm>。如果我在foo.cpp之后将其包含在<=>中,那么这个缺失的依赖关系将被忽视。相反,根据我刚刚提出的顺序,编译器会抱怨<=>尚未声明,允许我更正<=>。

在每个<!>“;库<!>中; group,我尝试按字母顺序排列include指令,以便更容易找到它们。

在旁注中,一个好的做法是最大限度地限制头文件之间的依赖关系。文件应包含尽可能少的标头,尤其是头文件。实际上,您包含的标头越多,在更改内容时需要重新编译的代码越多。限制这些依赖关系的一个好方法是使用前向声明,这在头文件中通常是足够的(请参阅何时可以使用前向声明?)。

Google C++ 风格指南、名称和包含顺序 :

在 dir/foo.cc 中,其主要目的是实现或测试 dir2/foo2.h 中的内容,按如下方式排序包含内容:

  • dir2/foo2.h(首选位置 - 请参阅下面的详细信息)。
  • C 系统文件。
  • C++ 系统文件。
  • 其他库的 .h 文件。
  • 您项目的 .h 文件。

我以前按字母顺序排序(更容易找到)

<!>“;如何<!>”;不明显,但<!>“什么<!>”;是。 您的目标是确保包含头文件的顺序永远不重要(我的意思是<!>“;从不!<!>”)。

一个很好的帮助是在构建仅包含其中一个的cpp文件(每个头文件一个)时测试头文件是否编译。

对于.cpp文件,您应该包括该类的标头或您首先要实现的任何内容,因此您将捕获此标头缺少某些包含的情况。之后,大多数编码指南首先包括系统标题,其次是项目标题,例如谷歌C ++风格指南

这是依赖性的东西,它在很大程度上取决于你在我们的标题中放置的内容。一个事实是,你可能真的臭名昭着,并尽量减少你的包含严格,但你最终会遇到一个你想要使用包含警卫的场景。

#ifndef MY_HEADER_H
#define MY_HEADER_H
//...
#endif

问题在开始时并不明显,但随着软件复杂性的增加,依赖关系也会增加。你可以做得很好,并且对它很聪明,但是更大的C ++项目通常都包含在内。你可以尝试,但你只能这么做。所以要勤奋并考虑你的包含,是的!但是你肯定会在某些时候有循环依赖,这就是你需要包含守卫的原因。

如果标头需要其他标头,那么它只是将它们包含在该标头中。

尝试构建代码,以便传递指针或引用,并在可能的位置转发声明。

在实现中,应首先列出定义它的标头(除非在Visual Studio中使用pch,否则stdafx将首先出现)。

我通常会根据需要列出它们。

我发现以下约定最有用:

module.cpp:

// this is the header used to trigger inclusion of precompiled headers
#include <precompiled.h> 
// this ensures that anything that includes "module.h" works
#include "module.h"
// other headers, usually system headers, the project

重要的是将模块的标头作为第一个非预编译的标头。这确保了<!> quot; module.h <!> quot;没有意外的依赖。

如果您正在处理磁盘访问时间较慢的大型项目,我已经看到这种样式用于减少构建时间:

module.cpp:

// this is the header used to trigger inclusion of precompiled headers
#include <precompiled.h> 
// this ensures that anything that includes "module.h" works
#include "module.h"
// other headers, usually system headers, the project
#if !defined _OTHER_MODULE_GUARD_
#include "other_module.h"
#endif 

#if !defined _ANOTHER_MODULE_GUARD_
#include "another_module.h"
#endif 

它有点冗长,但确实保存在磁盘上寻找,因为如果已经包含了标题,则不会搜索/打开标题。如果没有防护检查,编译器将寻找并打开头文件,解析整个文件以结束#ifdef整个文件。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top