【问题标题】:What order do I include header files in?包含头文件的顺序是什么?
【发布时间】:2011-07-30 09:18:31
【问题描述】:

我是编程新手,在我开始使用很多头文件后,头文件的话题让我有些不知所措。除此之外,我正在尝试使用预编译的标头。我也在使用 SFML 库,所以我有那些也必须包含在内的标题。

现在我有 stdafx.h、main.cpp,然后是 Ah、A.cpp、Bh、B.cpp、Ch、C.cpp、Dh 和 D 中包含的 A、B、C 和 D 类。 cpp.

如果

  • 所有类都包含一个 SFML 类的实例
  • D 类包含 A 类和 C 类的实例
  • C 类包含 B 类的实例 我的代码:(注意:所有标题都有标题保护)

stdafx.h:

#include <SFML/Graphics.hpp>
#include <iostream>

啊.h

#include "stdafx.h"
class A
{
    //sfml class
};

A.cpp

#include "stdafx.h"
#include "A.h"

B.h

#include "stdafx.h"
class B
{
    //sfml class
};

B.cpp

#include "stdafx.h"
#include "B.h"

C.h

#include "B.h"
class C: public B
{

};

C.cpp

#include "stdafx.h"
#include "C.h"

D.h

#include "A.h"
#include "C.h"
class D
{
    A a;
    C C; // if left uncommented I recieve a '1 unresolved externals' error
    //sfml class
}

D.cpp

#include "stdafx.h"
#include "D.h"

main.cpp

#include "stdafx.h"
#include "D.h"

【问题讨论】:

  • main.cpp 是否使用A,B,C,D 的任何类?
  • 有时这样想是有帮助的:当预处理器遍历你的文件时,它会将所有包含的头文件和cpp源文件放在一个大文件中,然后编译它。因此,将您的程序想象成一个大文件,然后考虑什么对顺序有意义。
  • 我通常按字母顺序按类别从高级到低级包含它们:核心(即标准)、平台(例如 Qt、Windows)、第 3 方库,然后是我的程序。使用包含守卫,顺序无关紧要,但是这样做可以更容易地查看那里有什么,以及在我使用类时是否需要添加一些东西。我也总是包含文件中使用的所有内容,即使我知道它包含在某处的标题中:标题可以更改,即使不经常发生,这使我的意图更清晰。

标签: c++ class header include precompiled


【解决方案1】:

我的理念是,在编写良好的代码中,头文件应该包含它们所依赖的所有其他头文件。我的理由是,不应该包含头文件并因此而出现编译器错误。因此,每个头文件都应该(在#ifdef 或#pragma once include guard 之后)包含它所依赖的所有其他头文件。

为了非正式地测试您是否记得在头文件中包含正确的头文件,*.cpp 文件应该#include 应该工作的最小头文件集。因此,如果A、B、C 和D 有单独的头文件,并且您的 cpp 文件使用类 D,那么它应该只包含 D.h。不会导致编译器错误,因为 Dh #includes Ah 和 Ch, Ch 包括 Bh 、Ah 和 Bh 包括 SFML 标头(无论是什么)。如果看起来合适,Ch 和 Dh 可以包含 SFML 标头,但如果您可以确定依赖项(Bh 啊) 已经包含了它。

然而,Visual C++ 执行“预编译头文件”的方式搞砸了这个逻辑。它要求您将"StdAfx.h"作为第一个头文件包含在内,这导致许多开发人员简单地将整个项目的所有#includes放在StdAfx.h中,并且不要在任何其他头文件中使用#include。我不推荐这个。或者,他们会将所有外部依赖项放在 StdAfx.h 中(例如 windows.h、boost 头文件)并在其他地方#include 本地依赖项,这样更改单个头文件不一定会导致整个项目重新构建。

按照我编写代码的方式,我的大多数 CPP 文件都包含 StdAfx.h 和相应的 .H 文件。所以 A.cpp 包括 StdAfx.h 和 A.h,B.cpp 包括 StdAfx.h 和 B.h,依此类推。放置在 cpp 文件中的唯一其他 #includes 是头文件未公开的“内部”依赖项。例如,如果类A 调用printf(),那么A.cpp(不是Ah)会调用#include &lt;stdio.h&gt;,因为Ah 会调用不依赖于 stdio.h。

如果你遵循这些规则,那么你#include 头文件的顺序无关紧要(除非你使用预编译头文件:那么预编译头文件在每个 cpp 文件中排在第一位,但不需要被包含在头文件中)。

【讨论】:

  • 我相信我正确地遵循了您的答案,但是当 Dh 包含 CI 类的实例时收到以下错误:致命错误 LNK1120: 1 unresolved externals 当实例被注释掉时,它编译得很好。跨度>
  • 它声称哪些外部未解决?您的示例不包含任何方法或全局变量。链接器不处理类本身(链接器主要处理函数和静态/全局变量),因此链接器在您上面发布的代码中没有什么可抱怨的。
【解决方案2】:

查看a similar question,了解创作标头的好方法。

简而言之,您希望在定义保护中定义每个标头,以防止标头在编译期间被包含超过一次。有了这些,对于每个 .h 和 .cpp 文件,只需包含解析任何声明所需的标题。预处理器和编译器将负责其余的工作。

【讨论】:

  • stdafx.h 包括 SFML 标头、A.h、B.h、C.h 和 D.h。我所有的标头都有标头保护,并且只包括 stdafx.h。我所有的源文件也只包含 stdafx.h。现在,每当我编译时,我都会收到大量“缺少类型”错误,我假设因为每个头文件在编译时只包含一次,因此使用该头文件的下一个类不包含它。这就是为什么我问我包含标题的顺序是什么。我使用的是 Microsoft Visual C++ 2010 Express Edition。
【解决方案3】:

C 继承类 B。所以,它应该看到标识符B。所以,在这里包括B.h -

#include "B.h"    // Newly added
// Or you can forward declare class B ; 
class C: public B
{

};

D 具有 A、B 类的对象。因此,在“D.h”本身中包含A, B 的标头。

class D
{
    A a;  // Should see the definition of class A
    C c;  // Should see the definition of class B
    //sfml class
}

D.cpp

#include "A.h"
#include "C.h"
#include "D.h"  // Notice that A.h and C.h should definitely placed before

请注意,每个标头都需要包含在其相应的源文件中。独立考虑每个源文件,并查看使用过的内容是否在源文件中较早定义。

【讨论】:

  • 由于某种原因 D.h 看不到 C 类的定义。
  • 奇怪的是,如果包含指向类 C 的指针,D 将编译,但如果它不是指针,我会得到一个未解决的外部错误。哦,好吧,我会解决这个问题。
【解决方案4】:

A.h 应该包含 SFML

A.cpp 应该包含 A.h

D.h 应包括 SFML、A.h 和 C.h

D.cpp 应该包含 D.h

main.cpp 应包括它直接使用的 A、B、C、D 和 SFML 中的任何一个。

通常在 .cpp 文件中,我不包含任何您知道必须包含在其相应 .h 中的标题,因为它们包含在该 .h 中定义的类的数据成员的定义。因此,在我的代码中 D.cpp 不会包含 A.h。不过,这只是我,您可能更喜欢包含它,只是为了提醒您 .cpp 文件(可能)使用它。

这留下了 stdafx - 你需要它的地方取决于它使用的东西。可能到处都需要它,并且 MSVC 不会处理(或处理但丢弃?)源文件中 #include "stdafx.h" 之前的任何内容,因此它应该是每个 .cpp 文件中的第一件事,并且不会出现在其他任何地方。

所有头文件都应该有多重包含保护。

您可以将 SFML(或您喜欢的任何其他内容)添加到 stdafx.h,在这种情况下,您不妨从其他任何地方删除这些包含。

完成此操作后,不再重要在每个文件中包含标题的顺序。所以你可以做你喜欢做的事,但我推荐Google's C++ style guide这个主题(点击箭头的东西),调整以考虑stdafx.h。

【讨论】:

    【解决方案5】:

    取决于依赖项。与 C# 和其他类似语言不同,C++ 按照编写顺序执行操作,因此可能存在问题。如果您确实对订单有问题,那么它将无法编译。

    【讨论】:

      猜你喜欢
      • 2019-03-07
      • 2015-10-18
      • 2021-11-23
      • 1970-01-01
      • 2011-12-11
      • 2011-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多