C ++标头顺序[关闭]
Posted
技术标签:
【中文标题】C ++标头顺序[关闭]【英文标题】:C++ Header order [closed] 【发布时间】:2010-10-11 11:42:28 【问题描述】:header/cpp 文件中的 headers 应该以什么顺序声明?显然,后续标头所需的那些应该更早,并且特定于类的标头应该在 cpp 范围内而不是标头范围内,但是是否有固定的顺序约定/最佳实践?
【问题讨论】:
【参考方案1】:在头文件中,您必须包含所有头文件才能使其可编译。并且不要忘记使用前向声明而不是某些标题。
在源文件中:
对应的头文件 必要的项目标题 第三方库标头 标准库头文件 系统头文件按此顺序,您将不会错过任何忘记自己包含库的头文件。
【讨论】:
我认为“必要的项目标头”应该在两个项目上分开: - 来自同一个库的项目标头; - 来自其他项目库的头文件(按照最常见项目库头文件的顺序,而不是一些特殊项目库头文件) 我真的很喜欢您的订购。这样,标头就不会依赖其他标头来包含它们的依赖项。 并在每个组中按字母顺序排列,以防止重复包含语句。 预编译的头文件应该是第一个。【参考方案2】:良好做法:每个 .h 文件都应该有一个 .cpp,它首先包含该 .h,然后再包含其他任何内容。这证明任何.h文件都可以放在首位。
即使标头不需要实现,您也可以创建一个仅包含该 .h 文件而不包含其他任何内容的 .cpp。
这意味着您可以以任何您喜欢的方式回答您的问题。将它们包含在什么顺序中并不重要。
如需更多精彩提示,请阅读这本书:Large-Scale C++ Software Design - 可惜它太贵了,但它实际上是 C++ 源代码布局的生存指南。
【讨论】:
我在单元测试中这样做。 更容易自动化测试:只需编译 (-c) 每个头文件(是的,g++ -c blah.h)并确保它可以编译。然后,您可以将目标文件扔掉。 +1,该答案中还有很多未说明的地方。很棒的提示! 你也可以用 VC++ 做到这一点:cl.exe /EHsc /TP /c blah.h @VadimFerderer 不幸的是,这不适用于作为具有许多附加路径(包括、库等)的复杂项目的一部分的标头。有什么简单的方法可以让 cl.exe 了解这些路径(它们是在项目文件中设置的)。【参考方案3】:在头文件中,我倾向于首先放置标准头,然后是我自己的头(两个列表都按字母顺序排列)。在实现文件中,我先放对应的头文件(如果有的话),然后是标准头文件和其他依赖头文件。
顺序并不重要,除非你充分利用宏和#define
;在这种情况下,您必须检查您定义的宏是否不会替换之前包含的宏(当然,除非您想要这样做)。
关于此声明
后续标题需要的应该更早
标题不应该依赖于它之前包含的其他标题!如果它需要标题,它只包含它们。标头保护将防止多重包含:
#ifndef FOO_HEADER_H
#define FOO_HEADER_H
...
#endif
编辑
自从我写了这个答案后,我改变了在我的代码中排序包含指令的方式。现在,我尝试始终将标头按标准化的递增顺序排列,因此我项目的标头排在第一位,然后是 3rd 方库标头,然后是标准标头。
例如,如果我的一个文件使用了我编写的库、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
中的<algorithm>
之后包含它,那么这种缺失的依赖关系将不会被注意到。相反,按照我刚才给出的顺序,编译器会报错std::copy
没有被声明,让我更正my_library.hpp
。
在每个“库”组中,我尽量保持包含指令按字母顺序排列,以便更轻松地找到它们。
顺便说一句,一个好的做法是最大程度地限制头文件之间的依赖关系。文件应包含尽可能少的标头,尤其是标头文件。事实上,你包含的头文件越多,当某些事情发生变化时,需要重新编译的代码就越多。限制这些依赖关系的一个好方法是使用前向声明,这在头文件中通常就足够了(参见When can I use a forward declaration?)。
【讨论】:
+1 用于包含/标题保护。【参考方案4】:Google C++ Style Guide, Names and Order of Includes:
在 dir/foo.cc 中,其主要目的是实现或测试 dir2/foo2.h 中的东西,按如下顺序排列您的包含:
dir2/foo2.h(首选位置 - 详情见下文)。 C 系统文件。 C++ 系统文件。 其他库的 .h 文件。 您项目的 .h 文件。
【讨论】:
是的,但是 ggl 风格指南中有一些讨厌的东西 :)【参考方案5】:我以前按字母顺序排列它们(更容易找到)
【讨论】:
这也是 Epic 的做法,在他们的虚幻引擎 4 风格文档中。【参考方案6】:“如何”并不明显,但“是什么”是显而易见的。 您的目标是确保包含头文件的顺序不重要(我的意思是“从不!”)。
一个很好的帮助是在构建只包含其中一个的 cpp 文件(每个头文件一个)时测试头文件是否编译。
【讨论】:
【参考方案7】:对于 .cpp 文件,您应该包含类的标头或您首先要实现的任何内容,这样您就可以捕捉到该标头缺少某些包含的情况。之后,大多数编码指南倾向于首先包含系统标头,然后是项目标头,例如Google C++ Style Guide。
【讨论】:
【参考方案8】:这是一个依赖关系,很大程度上取决于您在我们的标头中放入的内容。事实是,您可能对此非常臭名昭著并尽量减少以保持您的包含严格,但您最终会遇到需要使用包含保护的情况。
#ifndef MY_HEADER_H
#define MY_HEADER_H
//...
#endif
问题在开始时并不那么明显,但随着软件复杂性的增加,您的依赖项也随之增加。您可以做得很好,并且对此很聪明,但是较大的 C++ 项目通常充满了包含。你可以尝试,但你只能做这么多。所以要勤奋,想想你的包括,是的!但是你肯定会在某些时候有循环依赖,这就是你需要包含保护的原因。
【讨论】:
这和调用 '#pragma once' 不一样吗? 是的(或多或少)相同,但 #pragma once 不是标准的。 据记录,#pragma once 是 Microsoft 扩展。如果我正在处理一个多平台项目,我会使用它以及包含保护,因为 #pragma once 实际上会阻止解析文件。 #pragma once 在大多数 C++ 编译器(包括 G++)中都能正常工作。【参考方案9】:如果一个标头需要其他标头,则只需将它们包含在该标头中即可。
尝试构造您的代码,以便您传递指针或引用并在可能的地方转发声明。
在实现中,定义它的标头应该首先列出(在 Visual Studio 中,如果您使用的是 pch,则 stdafx 将首先列出)。
我通常会根据需要列出它们。
【讨论】:
【参考方案10】:我发现以下约定最有用:
模块.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”没有意外的依赖关系。
如果您正在处理一个磁盘访问时间很慢的大型项目,我已经看到这种风格用于减少构建时间:
模块.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
ing 整个文件。
【讨论】:
以上是关于C ++标头顺序[关闭]的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Linux 上用 C/C++ 编写 Web 服务器 [关闭]