C ++标题顺序

时间:2009-03-05 10:49:40

标签: c++ header include code-organization

标头/ cpp文件中应声明标头的顺序是什么?显然,后续标题所需的那些应该更早,类特定标题应该在cpp范围内而不是标题范围,但是是否有一个集合顺序约定/最佳实践?

10 个答案:

答案 0 :(得分:63)

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

在源文件中:

  • 相应的头文件
  • 必要的项目标题
  • 第三方图书馆标题
  • 标准库标题
  • 系统标题

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

答案 1 :(得分:21)

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

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

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

有关更多精彩提示,请尝试使用本书:Large-Scale C++ Software Design - 这太遗憾了,但它实际上是C ++源代码布局的生存指南。

答案 2 :(得分:6)

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

顺序并不重要,除非您充分利用宏和#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>。如果我在<algorithm> foo.cpp之后将其包含在内,则会忽略此缺失的依赖关系。相反,根据我刚才提出的顺序,编译器会抱怨std::copy尚未声明,允许我更正my_library.hpp

在每个“库”组中,我尝试按字母顺序排列include指令,以便更容易地找到它们。

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

答案 3 :(得分:5)

Google C++ Style Guide, Names and Order of Includes

  

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

     
      
  • dir2 / foo2.h(首选地点 - 见下文详情)。
  •   
  • C系统文件。
  •   
  • C ++系统文件。
  •   
  • 其他图书馆的.h文件。
  •   
  • 您项目的.h文件。
  •   

答案 4 :(得分:3)

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

答案 5 :(得分:2)

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

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

答案 6 :(得分:1)

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

答案 7 :(得分:0)

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

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

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

答案 8 :(得分:0)

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

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

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

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

答案 9 :(得分:-1)

我发现以下约定最有用:

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

重要的是将模块的标头作为第一个非预编译的标头。这可以确保“module.h”没有意外的依赖关系。

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

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整个文件。