8

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

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

如果在所有文件中包含标题,我会以什么顺序进行

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

stdafx.h:

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

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

A.cpp

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

溴化氢

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

B.cpp

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

通道

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

};

C.cpp

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

DH

#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"

主文件

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

5 回答 5

10

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

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

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

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

如果您遵循这些规则,那么#include头文件的顺序就无关紧要了(除非您使用预编译头文件:那么预编译头文件首先出现在每个 cpp 文件中,但不需要包含在头文件中)。

于 2011-04-05T23:22:29.853 回答
1

看看一个类似的问题,了解创作标题的好方法。

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

于 2011-04-05T22:54:00.147 回答
1

啊应该包括SFML

A.cpp 应该包括 Ah

Dh 应包括 SFML、Ah 和 Ch

D.cpp 应该包括 Dh

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

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

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

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

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

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

于 2011-04-05T22:56:41.050 回答
1

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

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

};

D有类的对象ABA, B因此,在“Dh”本身中包含标题。

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

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

于 2011-04-06T01:04:11.937 回答
0

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

于 2011-04-05T23:14:56.620 回答