为什么我需要转发声明 class foo 而不是 class bar,即使 'foo.h' 和 'bar.h' 都包含在内?
Why do I need to forward declare class foo but not class bar, even though 'foo.h' and 'bar.h' are both included?
我在尝试编译此代码时收到 C2143 错误;我通过前向声明 class Level
修复了它,但我对为什么需要这样做感到困惑,因为我已经包含了 #include Level.h
,这当然是定义 Level
的地方。不过,更让我困惑的是,我 似乎不需要 对同一个地方的类似陈述采取相同的措施。这是我的代码:
// global.h
// Global variables
#pragma once
#include "Level.h"
#include "view.h"
#include "ActorPlayer.h"
class Level; // Without this line C2143 (missing ; before *) is
// generated after 'extern Level'
extern Level* gamelevel;
extern View* view;
extern bool gameover;
extern bool player_turn;
extern int game_ticks;
extern ActorPlayer* act_player;
我的问题是,为什么我不需要 class View;
和 class ActorPlayer;
?相关区别是什么?
万一重要,这里是Level.h:
// Level.h
// Header file for Level class
#pragma once
#include "Terrain.h"
#include "global.h"
#include "hex_math.h"
class Level
{
public:
const int WIDTH;
const int HEIGHT;
Level();
Level(int width, int height);
Level(int radius);
~Level();
bool isInBounds(OrdPair coord);
int terrainAt(OrdPair coord);
void update();
private:
int** terrain;
void init();
void fillHex(int qCenter, int rCenter, int radius, int terrainID);
};
问题是您对包含文件存在循环依赖:
global.h includes level.h
level.h includes global.h
发生的事情是
- 编译器开始读取
level.h
- 读取
pragma once
将文件标记为已包含
- 找到
global.h
并开始阅读(此时)
- 读取
pragma once
将文件标记为已包含
- 发现包含
level.h
但忽略它(它被标记为包含在 2 中)
- 继续阅读
global.h
的其余部分,但 class Level
未知
如果项目不是微不足道的,你应该制作一个你的 classes 和模块的图表,并决定什么依赖于(建立在)什么上。这个图应该是一个 DAG(没有循环)。更具体地说,应该可以细分 "layers" 中的模块,其中较低层的模块不依赖于较高层中的模块。
如果你的依赖关系图中有一个循环,项目将更难处理(例如单元测试),因为你的模块不是真正的模块,而是整个程序变成了一个巨大的代码球。
在 global.h 中包含 Level.h,但在 Level.h 中包含 global.h。这个问题很可能是由于循环依赖造成的。
#pragma once的思想其实并不是为了防止循环依赖,而是为了防止一个文件被包含两次。
#pragma once 在您的特定情况下是否有效实际上取决于您使用的编译器。
最简单的解决方案是完全避免循环依赖。
我在尝试编译此代码时收到 C2143 错误;我通过前向声明 class Level
修复了它,但我对为什么需要这样做感到困惑,因为我已经包含了 #include Level.h
,这当然是定义 Level
的地方。不过,更让我困惑的是,我 似乎不需要 对同一个地方的类似陈述采取相同的措施。这是我的代码:
// global.h
// Global variables
#pragma once
#include "Level.h"
#include "view.h"
#include "ActorPlayer.h"
class Level; // Without this line C2143 (missing ; before *) is
// generated after 'extern Level'
extern Level* gamelevel;
extern View* view;
extern bool gameover;
extern bool player_turn;
extern int game_ticks;
extern ActorPlayer* act_player;
我的问题是,为什么我不需要 class View;
和 class ActorPlayer;
?相关区别是什么?
万一重要,这里是Level.h:
// Level.h
// Header file for Level class
#pragma once
#include "Terrain.h"
#include "global.h"
#include "hex_math.h"
class Level
{
public:
const int WIDTH;
const int HEIGHT;
Level();
Level(int width, int height);
Level(int radius);
~Level();
bool isInBounds(OrdPair coord);
int terrainAt(OrdPair coord);
void update();
private:
int** terrain;
void init();
void fillHex(int qCenter, int rCenter, int radius, int terrainID);
};
问题是您对包含文件存在循环依赖:
global.h includes level.h
level.h includes global.h
发生的事情是
- 编译器开始读取
level.h
- 读取
pragma once
将文件标记为已包含 - 找到
global.h
并开始阅读(此时) - 读取
pragma once
将文件标记为已包含 - 发现包含
level.h
但忽略它(它被标记为包含在 2 中) - 继续阅读
global.h
的其余部分,但 classLevel
未知
如果项目不是微不足道的,你应该制作一个你的 classes 和模块的图表,并决定什么依赖于(建立在)什么上。这个图应该是一个 DAG(没有循环)。更具体地说,应该可以细分 "layers" 中的模块,其中较低层的模块不依赖于较高层中的模块。
如果你的依赖关系图中有一个循环,项目将更难处理(例如单元测试),因为你的模块不是真正的模块,而是整个程序变成了一个巨大的代码球。
在 global.h 中包含 Level.h,但在 Level.h 中包含 global.h。这个问题很可能是由于循环依赖造成的。
#pragma once的思想其实并不是为了防止循环依赖,而是为了防止一个文件被包含两次。
#pragma once 在您的特定情况下是否有效实际上取决于您使用的编译器。
最简单的解决方案是完全避免循环依赖。