我正在使用SFML创建一个Snake游戏,我有一个具体的类SnakeGame
,它包含我班级的所有数据成员,例如窗口大小,游戏地图的大小,蛇的颜色,因此,我班级的内部成员看起来像这样:
class SnakeGame
{
private:
//....
const sf::Vector2u windowSize{400, 336};
const sf::Color snakeColor {0, 0, 0};
//...etc...
public:
SnakeGame() :
renderWindow {sf::VideoMode{windowSize.x, windowSize.y}, /*other arguments*/ },
snake {snakeColor, /*other arguments*/}
/*etc*/
{}
然而,这不起作用,我得到一个看不见的窗口,让我相信参数还没有构建。在阅读了另一篇SO帖子之后,我读到const
成员作为类的成员不会在编译时进行评估,而是在运行时实例化类,并且它们的行为方式与const
完全相同变量。因此,当我在windowSize
中实例化snakeColor
时,会评估变量SnakeGame
和main
,因此我无法在我的类的初始化列表中使用它们。为了尝试解决这个困境,我决定切换到static constexpr
变量,但不幸的是我意识到sf::Vector<T>
没有constexpr
构造函数,sf::Color
也没有。当然,我想我可以切换到整数类型,例如static constexpr unsigned int
作为窗口大小,但最终会变得重复,特别是对于颜色。所以我决定采取另一种方式。我所做的是创建另一个文件GameData.hpp
,并在其中执行此操作:
namespace gd //For game data
{
const sf::Vector2u windowSize{400, 336};
const sf::Color snakeColor {0, 0, 0};
//...etc...
}
但是,我不喜欢这个解决方案,因为即使现在在编译时评估这些数据,如果它们包含适当的头文件,也可以访问我的所有类,而不仅仅是SnakeGame
。通过这种方式,我觉得我的班级的内部数据结构正在被揭示。这导致了我的问题,即:是否有办法强制在编译时对类的const
成员进行评估,使得这些变量可以在初始化列表中使用,并保证他们会构建吗?
答案 0 :(得分:2)
这里有几个选项,所有选项都有权衡。我把它们按照我认为最好的最差的顺序排列,但你的权衡可能会有所不同。
snakeColor
成为inline static const
变量。如果你想要一个只有头文件库并且可以使用C ++ 17,这是最好的选择。const static
数据成员,并将const sf::Color SnakeGame::snakeColor {0, 0, 0}
添加到一个.cpp
文件中。如果您不需要仅包含标头的库,这是最佳选择。getColor
static const sf::Color& getSnakeColor()
方法,其中包含static
常量,然后返回。 static
关键字在函数内部的含义略有不同,然后您可以在此处执行所需操作。但是,这意味着您需要更改使用方式的语法。namespace snake
中,那么您将这些变量放在snake::details
中,那么按照惯例,人们就会知道他们不应该看到那里。与其他选项不同,这不是强制执行的。Vector2u
和Color
成为文字类型,以便您可以使用constexpr
。显然这需要更长时间,并且不能保证有效。我可能还有其他选择。例如,有一种涉及帮助器模板类的方法,您可以使用它来获取仅包含头的库,不需要inline
成员变量支持,也无需切换到函数调用来访问数据,以及{强制执行{1}}说明符。我不太记得如何使它工作,而且它比通常值得复杂。