我正在写一个简单的游戏,我已经完成了,除了它有一个糟糕的文件结构,每个类只是一个.h文件。
我决定将声明和定义拆分成单独的文件,因为我遇到了循环包含问题(这是可预测的)。
现在我已将它们拆分为单独的文件,我的.h文件包含:
虽然我的.cpp文件包含:
好的,既然你对我的文件结构有一个大概的了解,那就是我遇到的问题。
Spaceship.cpp需要Core.h中存在的cursorPos变量
Core.h包含Spaceship.h,因为它需要一个方法。
如果我在Spaceship.h中包含Core.h,我会得到双重声明。
如果我在Spaceship.h中没有包含Core.h,我就不会声明。
我很无能,我应该创建一个'Helper'类,其中包含我想在类之间交叉共享的变量吗?
修改 代码要求
Spaceship.h
#pragma once
#ifndef SPACESHIP_H
#define SPACESHIP_H
#include "Vector2D.h"
#include "Entity.h"
#include "Missile.h"
#include <SDL.h>
#include "Core.h"
extern const int SPACESHIP_SHOOT_DELAY = 50;
extern const int SPACESHIP_MAX_VELOCITY = 10;
extern const float SPACESHIP_VELOCITY_GAIN = 0.05;
extern const float SPACESHIP_VELOCITY_LOSS = -0.15;
class Spaceship : public Entity
{
public:
Vector2D position = Vector2D(0, 0);
Vector2D direction = Vector2D(0, 0);
SDL_Texture* texture;
//Required by rendering
SDL_Rect renderbox = { 0, 0, 32, 32 };
SDL_Rect boundingbox = { 0, 0, 32, 32 };
SDL_Point center = { 16, 16 };
int lastShot = SDL_GetTicks();
int angle = 0;
float velocity = 0;
void Update() override;
void Render(SDL_Renderer* renderer) override;
void Fire();
Spaceship();
~Spaceship();
};
#endif
Core.h
#pragma once
#ifndef CORE_H
#define CORE_H
#include "Vector2D.h"
#include <SDL.h>
#include "Spaceship.h"
extern Vector2D cursorPos = Vector2D();
class Core
{
private:
static bool run;
public:
static SDL_Window* window;
static SDL_Renderer* renderer;
static SDL_Cursor* cursor;
static int screenWidth;
static int screenHeight;
static void Initialize();
static void ProcessEvents(SDL_Event* e);
static void Update();
static void Render();
static int Execute();
static void Cleanup();
Core();
~Core();
};
#endif
答案 0 :(得分:1)
变量的定义也应该位于.cpp文件中。标题应使用extern
关键字声明:
Core.h:
extern Point cursorPos;
Core.cpp:
#include "Core.h"
...
Point cursorPos;
答案 1 :(得分:0)
将#pragma once
作为每个头文件的第一行。这解决了多次包含的问题(即它将确保编译器不会重新包含之前已包含的包含文件的代码)
答案 2 :(得分:0)
使用全局变量是一种反模式,并且有充分的理由。然而,描述为什么人们应该避免全球状态的所有原因,是另一天的主题。在您的情况下,您在全局变量的特定实现方面遇到问题。虽然我强烈建议您重新审视您的设计,并降低全局状态的数量,但我会尝试为您遇到的问题提供解决方案和解释。
一个问题是理解C ++的包含机制,当您在C ++中包含文件时,您基本上是在代码中的那个位置插入该文件的内容。因此,如果您在头文件中声明了任何内容,则会将其声明为包含它的位置。如果多次包含文件,则会多次插入,从而多次声明变量。作为一个例子,考虑我的标题variables.h:
int someGlobalVariable = 100;
现在考虑第二个头文件:functional.h,如下所示:
#include "variables.h"
void foo(int number);
最后是一个名为functional.cpp的源文件:
#include "variables.h"
#include "functionality.h"
void foo(int number) {
// Do something
}
这将给出编译器错误,因为我们的变量someGlobalVariable被定义了两次。但为什么会这样呢?如果我们尝试包含,我们将看到原因:
// variables.h
int someGlobalVariable = 100;
// functionality.h
int someGlobalVariable = 100; // <-- included from functionality.h
void foo(int number);
void foo(int number) {
// Do something
}
正如你所看到的那样,变量被插入了两次,而且当然不好,编译会抱怨,并且有充分的理由。 foo
的前瞻声明完全合法。
我们可以在我们的头文件中添加包含警卫:
文件variables.h:
#ifndef VARIABLES_H_
#define VARIABLES_H_
int someGlobalVariable = 100;
#endif
文件功能.h:
#ifndef FUNCTIONALITY_H_
#define FUNCTIONALITY_H_
#include "variables.h"
#include "functionality.h"
void foo(int number) {
// Do something
}
#endif
这会导致someGlobalVariable
变量只包含在我们的.cpp源文件中一次。然而,这并不能使它真正具有全球性。请记住,因为C ++在我们包含文件的位置插入文件的内容,所以我们仍然会为包含它的每个源独立源文件声明一次该变量。
对于每个源模块,我们都会有一个新的实例,而不是全局的,这不是你想要的。您需要确保变量仅声明一次,然后引用。这意味着我们需要在未包含的文件中声明变量(或者最多包含一次)。让我们把它放在一个.cpp文件中。
这是一个名为globals.cpp的.cpp文件:
int someGlobalVariable.cpp = 100;
现在需要将variable.h文件修改为:
#ifndef VARIABLES_H_
#define VARIABLES_H_
extern int someGlobalVariable;
#endif
extern
关键字指示链接器在另一个源单元中声明变量。因此,当我们插入包含:
// variables.h
extern int someGlobalVariable;
// functionality.h
// Since VARIABLES_H_ is now defined we will not insert the contents.
void foo(int number);
void foo(int number) {
// Do something
}
然后链接器将知道在另一个目标文件中查找someGlobalVariable的声明。最重要的是,所有引用extern int someGlobalVariable
的源单元都将共享同一个实例。
在您的情况下,您应该从声明中删除=
,该变量应在其自己的源单元中声明。所以你的行:
extern Vector2D cursorPos = Vector2D();
变为:
extern Vector2D cursorPos;
然后在源(.cpp)文件中声明变量如下:
Vector2D cursorPos = Vector2D();