8

Some months ago I created a C# Project of a game called Vexed. Now I'm creating a Tetris, but in C++. Basically I want to use the same logic I used in the other project, it was a little bit like this:

I created a Class called "Game" where there was all the information about the game. It had it's methods, variables and everything. Then, I created a static class called "PublicInstances" or something like that, and in that class I declared something like this:

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

It made it so simple to use then, because any change I made on the game was saved in that static instance of my class and I could access it anywhere on the project. I want to know how to do exactly that with C++, to create a public or global instance of my class Game so I can access it and change it everywhere and have everything updated in any Form or class of my project. I would really appreciate your help.

// Sorry if my English isn't the best ^^

avatarbobo
  • 269
  • 2
  • 6
  • 14
  • 1
    if u really want a global, u don't have to put it inside a class. just declare it in a header and define in a source file. but globals (or globally accessible statics) are usually bad design – Kal Oct 02 '13 at 04:31
  • My main problem is that I usually travel between Forms, and I need to get information from one place to another, how could I change the use of a global variable or class? – avatarbobo Oct 02 '13 at 04:37
  • It sounds as if `TetrisGame` should be a namespace, not an object. That will also eliminate the need to define a class type for it. – Ben Voigt Oct 02 '13 at 04:42
  • I agree with the fact that this design is probably a bit flawed but, that's beyond the question. Anyways, I'd still suggest you to reconsider. – MasterMastic Oct 02 '13 at 04:55

1 Answers1

12

Revisited and summarised

Option 1

You may simply declare and define a global instance of Game object. In a header file, e.g. game.h:

extern Game globalGameObj;

When you include game.h in a source file globalGameObj name becomes visible. You also need to create an actual object. In a source file, e.g. game.cc (outside of any class):

Game globalGameObj;

Access it by the variable name:

globalGameObj.do_some_work();

Option 2

Use a pattern often called singleton. Add the following to your Game class (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*/}
};

You access Game instance with shared_instance() method:

Game::shared_instance().do_some_work();

You do not use anything like your static class PublicInstances in the above. C++ allows you to introduce a namespace (e.g. PublicInstances) to provide name isolation and keep your global objects in one place but it'll probably to be an overkill. In any case if you have few global objects then it is likely to be a bad design.

What option is better? Some people would argue that singleton pattern should be used. It guarantees that only a single instance is created. However both option 1 and option 2 have the same problem: they introduce a global object in your code with all disadvantages attributed to global variables. I'd say that singleton is a global object in disguise. I do not see deciding technical reasons in favour of either option so I'd say that it is a matter of personal taste.

Historical note :)

My first suggestion for Option 2 was to use a dynamically allocated Game object rather than a function local static object.

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

Few people suggested that it was not the best way anymore, thank you Kal, argiopeweb and Simple. C++03 has issues initialising static objects in presence of threads. C++11 guarantees safe initialisation of statics.

C++11 draft, secion 6.7

such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. [...] If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.

giraffesyo
  • 4,860
  • 1
  • 29
  • 39
dmitri
  • 3,183
  • 23
  • 28
  • 1
    You've declared `S::_inst` but you haven't defined it. – Adam Oct 02 '13 at 04:42
  • 1
    also a better way to do this is `static S& instance() { static S inst; return inst; }` – Kal Oct 02 '13 at 04:48
  • @BenVoigt Is it not clear what you mean, no class needed. Game class is there by default. – dmitri Oct 02 '13 at 05:04
  • @dmitri actually u can; the ctor is called when the function is called for the first time. also u can pass parameters to the ctor, just like `static S inst { 1, 2 };` or whatever – Kal Oct 02 '13 at 05:07
  • In regards to the drawback with option #2, this is no longer the case with C++11 as per n2660: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm – Elliot Robinson Oct 02 '13 at 05:54
  • @avatarbobo the way it works is by essentially returning a static reference to a single instance of itself, instansiation is made impossible outside of the class by making the default constructor private – Matthew Pigram Oct 03 '13 at 05:04
  • He was not looking for singleton, he was looking for static instance. Option 2 do not resolve the problem. Option 1: I can't understand how to assign value to this game. – Vincent Guyard Aug 12 '22 at 22:32
  • @VincentGuyard, the OP asked how to create a global object in C++. Singleton pattern is used for that. In any case, Option 2 is complimentary. How to assign value to what? `Game globalGameObj` is a constructor; it initialises Game members. You will also have methods to manipulate Game object members. – dmitri Aug 18 '22 at 23:43