如何在C++中声明一个静态类实例?

8

几个月前,我创建了一个名为Vexed的游戏的C#项目。现在我正在用C++创建俄罗斯方块。基本上,我想使用在另一个项目中使用的相同逻辑,它有点像这样:

我创建了一个名为“Game”的类,其中包含有关游戏的所有信息。它有它的方法、变量和一切。然后,我创建了一个静态类,名为“PublicInstances”或类似的东西,在那个类中,我声明了如下内容:

static class PublicInstances
{
    public static Game vexedGame = new Game(); //This is C# and works.
}

它使得使用变得非常简单,因为我在游戏上所做的任何更改都保存在我的类的静态实例中,我可以在项目的任何地方访问它。我想知道如何在C ++中创建一个公共或全局实例,以便我可以随时访问并更改它,并在项目的任何窗体或类中更新所有内容。非常感谢您的帮助。//如果我的英语不是最好的话,请见谅^^

1
如果你真的想要一个全局变量,你不必将它放在类内部。只需在头文件中声明并在源文件中定义即可。但是全局变量(或全局可访问的静态变量)通常是不好的设计。 - Kal
我的主要问题是我经常在窗体之间旅行,我需要从一个地方获取信息并传递到另一个地方,我该如何改变全局变量或类的使用? - avatarbobo
听起来TetrisGame应该是一个命名空间,而不是一个对象。这也将消除为其定义类类型的需要。 - Ben Voigt
我同意这个设计可能有些缺陷,但是这已经不是问题了。无论如何,我仍然建议你重新考虑一下。 - MasterMastic
1个回答

13

重新审视和总结

选项1

您可以简单地声明并定义一个全局的Game对象实例。 在头文件中,例如game.h:

extern Game globalGameObj;

当你在源代码文件中包含game.h时,globalGameObj名称会变得可见。 你还需要创建一个实际的对象。在源代码文件(例如game.cc)中(不属于任何类):

当您在源文件中包含game.h时,全局变量globalGameObj的名称就会变得可见。 此外,您还需要创建一个实际的对象。在源文件中(比如game.cc)(不属于任何类):

Game globalGameObj;

通过变量名访问它:

globalGameObj.do_some_work();

选项2

使用经常被称为单例的模式。在您的游戏类(game.h)中添加以下内容:

class Game
{
  public:
    static Game &shared_instance() {static Game game; return game;}

  private:
    // Make constructor private. Only shared_instance() method will create an instance.
    Game() {/*whatever initialisation you need*/}
};
您可以使用 shared_instance() 方法来访问 Game 实例:
Game::shared_instance().do_some_work();

在上面的代码中,您没有使用类似于static class PublicInstances的东西。C++ 允许您引入命名空间(例如PublicInstances)以提供名称隔离并将全局对象保留在一个位置,但这可能会过度设计。无论如何,如果您只有少量的全局对象,那么很可能是一个不好的设计。

哪个选项更好?一些人会认为应该使用单例模式。它保证只创建一个实例。然而,选项 1 和选项 2 都有相同的问题:它们在您的代码中引入了一个全局对象,带有所有归因于全局变量的缺点。我会说单例模式是伪装成全局对象的东西。我没有看到任何技术上有利于任何一种选项的原因,所以我认为这是个人口味的问题。

历史注记 :)

对于选项 2,我的第一个建议是使用动态分配的 Game 对象而不是函数局部静态对象。

static Game *instance() {if (!_inst) _inst = new Game(); return _inst;}

有些人提出这不再是最好的方法,感谢KalargiopewebSimple。在存在线程的情况下,C++03存在初始化静态对象的问题。C++11保证了静态变量的安全初始化。

C++11草案第6.7节

如果这样的变量在其声明中首次通过控制,则将初始化此类变量; 只有在其初始化完成后才被认为已初始化[...]。 如果在变量正在初始化时并发地进入声明, 并发执行应等待初始化完成。


1
你已经声明了 S::_inst 但你没有定义它。 - Adam
1
另一种更好的方法是 static S& instance() { static S inst; return inst; } - Kal
@BenVoigt,您的意思不清楚吗?不需要类。游戏类已经默认存在。 - dmitri
关于选项#2的缺点,根据n2660,这在C++11中不再是问题:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm - Elliot Robinson
@avatarbobo 它的工作原理是通过基本上返回对其自身单个实例的静态引用来实现的,通过使默认构造函数私有化,使类外部无法进行实例化。 - Matthew Pigram
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接