1

尝试在 VS2010 上构建我的解决方案时,我变得疯狂、神秘的编译器错误。我真的很难理解这些包括工作。

Game.cpp
Game.h
Deck.cpp
Deck.h
Card.h

// Game.cpp
#include "Game.h"

都好。现在我需要创建一个新牌组:

// Game.h
private:
    static Deck _deck;

那么我需要包含 Deck.h 以便它知道它是什么:

// Game.h
#include "Deck.h"
class Game {
private:
    Deck _deck;
}

好的,没关系。但现在我需要使用 Game.cpp 中的 _deck

// Game.cpp
#include "Game.h"
Deck Game::_deck;
void Shuffle(void)
{
     _deck = Deck();
     _deck.Shuffle();
}

但我收到一条错误消息,提示“Deck 未定义”。但是既然 Game.cpp 包含 Game.h,Game.h 应该包含 Deck.h 吗?

如果我将 Deck.h 添加到 Game.cpp 我得到:

"Uses undefinied class Deck Game.cpp"

"Deck class redeclaration Deck.h"

我完全不明白这个...

4

3 回答 3

2

你应该看到这个解释包括警卫的stackoverflow问题

为什么在 C++ 头文件中使用 #ifndef 和 #define?

于 2013-02-25T23:42:25.257 回答
1

#include是在编译器之前运行的预处理器阶段的一部分,基本上执行文本的替换。

您描述的问题与翻译单位有关。基本上,您可以认为源文件(.c、.cpp、.inl 等)与头文件(.h、.hpp)不同,因为每个源文件都定义了编译器可以执行的翻译单元操作。源文件基本上由文件中的所有逻辑加上它直接或间接引用的所有包含组成。

编译器将从每个翻译单元构建目标文件,然后链接器的工作是将它们全部放在一个库或可执行二进制文件中。在链接时间之前,其他源文件中的逻辑不能立即用于任何其他源文件或头文件。

最容易记住的是,头文件定义了你的接口,而源文件定义了你的实现。您希望您的头文件尽可能轻巧,并且尽可能多地避免实现细节,以提高编译时间速度并放松对象之间的耦合。为此,您需要依赖头文件中的前向声明并尝试在其他头文件中保留尽可能少的 .h 引用,而不是将它们移动到源文件中。

许多现代语言混合了接口和实现这两个概念,并且借助新 IDE 的强大功能,这不是什么大问题。然而,我仍然回顾并欣赏 C++ 中的分离,因为这种方法更加明确。编写良好的类的客户端应该能够忽略实现细节,因此他们应该只需要看到标题才能使用该类。当您使用 C++ 处理库时,通常会出现这种情况,因为您可能只能访问头文件。

于 2013-02-25T23:54:53.273 回答
1

你有一个循环包含。幸运的是,static成员在声明时不需要完整定义,因此您可以在 Game.h 中包含前向声明:

// Game.h
class Deck;

//....
private:
    static Deck _deck;
于 2013-02-25T23:43:54.563 回答