0

What would be a good method of defining wrapper class objects (outside of main) in a large framework that need to be implemented, in a way, which they can be accessed from anywhere.

(e.g. using Clock.Get_Deltatime() in gameobjects like Player.cpp and yet running Clock.Update() in main.cpp)

Can I do something like this?

#ifndef PLUGIN_H
#define PLUGIN_H

#include "DisplayManager.h"
#include "EventHandler.h"
#include "Time.h"

DisplayManager Display;
EventHandler Input;
Time Clock;

#endif PLUGIN_H

Than include Plugin.h anytime I need to access Display, Clock and Input? Considering this, singletons and static variables right now, but am looking for suggestions and want to know what will work best for this situation (I'm relatively new to C++ and don't have enough OOP experience to know whats the best tool for the job).

Reign
  • 3
  • 3

2 Answers2

1

The code above will work but you need to declare the variables with the extern keyword so that the compiler doesn't generate a new global variable each time the header is included. In one place in your application declare the global variable without the extern keyword and that will be the place where the variable is actually initialized.

Instead of the above I suggest the following pattern. I will Use DisplayManager as an example:

DisplayManager.h:

#ifndef DISPLAY_MANAGER_H_
#define DISPLAY_MANAGER_H_

class DisplayManager {
 public:
  static DisplayManager* Get();

  // Any other public interfaces.

 private:
  // Declare the constructor private or protected to prevent instances other
  // than the singleton.
  DisplayManager();
  ~DisplayManager();

  // Any other private functions or members.
};

DisplayManager.cpp:

#include "DisplayManager.h"

static DisplayManager* g_display_manager;

DisplayManager* DisplayManager::Get() {
  if (!g_display_manager) {
     g_display_manager = new DisplayManager();
  }
  return g_display_manager;
}

...

This approach encapsulates the singleton behavior within the classes themselves.

Reilly Grant
  • 5,590
  • 1
  • 13
  • 23
  • I can see how the `extern` keyword would be tedious, but wouldn't the inclusion guards prevent multiple instances of the instances? I suppose I could test it by using a static variable to count them and include `plugins.h` several times. Still researching if Singletons are a good way to go. I think they'll work, but they seem to be really disliked. http://stackoverflow.com/questions/86582/singleton-how-should-it-be-used – Reign Dec 08 '14 at 10:11
  • Inclusion guards will keep the compiler from failing for multiple declarations of the same variable. However, every source file in which you include this header file will have it OWN instance of the classes. By using extern, the compiler knows not to create a new instance of the object and will let the linker resolve that. You then need an instance of the objects to be instantiated in a non-header file. – Charley Moore Dec 10 '14 at 01:19
  • Singletons are perfectly acceptable if you use them correctly and for the right reasons. People are down on them only because they can be abused like global variables. – Charley Moore Dec 10 '14 at 01:21
  • Oh, I see. Guess I'll go with singletons than. Thanks. – Reign Dec 12 '14 at 09:09
1

This answer uses C++11

In a single threaded environment, the follow pattern for a singleton works well:

#include <memory>

class DisplayManager
{
public:
  static DisplayManager* instance()
  {
    static std::unique_ptr<DisplayManager> ptr(new DisplayManager);
    return ptr.get();
  }
private:
  friend struct std::default_delete<DisplayManager>;
  DisplayManager() {}
  ~DisplayManager() {}
  DisplayManager(const DisplayManager& rhs) {}
  DisplayManager& operator= (const DisplayManager& rhs) { return *this; }
};

If you need to ensure correct access from multiple threads, change it to:

#include <memory>
#include <mutex>

class DisplayManager
{
public:
  static DisplayManager* instance()
  {
    static std::unique_ptr<DisplayManager> ptr;
    static std::mutex m;
    if (!ptr)
    {
      m.lock();
      if (!ptr) ptr.reset(new DisplayManager);
      m.unlock();
    }
    return ptr.get();
  }
private:
  friend struct std::default_delete<DisplayManager>;
  DisplayManager() {}
  ~DisplayManager() {}
  DisplayManager(const DisplayManager& rhs) {}
  DisplayManager& operator= (const DisplayManager& rhs) { return *this; }
};
Photon
  • 3,182
  • 1
  • 15
  • 16
  • Currently using MS visual studio 2012 express edition. Which apparently uses 199711. From what I can tell its version C++ 98, unfortunately. The 2D game engine I'm writing does not use multiple threads. – Reign Dec 08 '14 at 08:43
  • If you don't need multiple threads, you can still use the above code with some adjustments. Mainly replace the unique_ptr with an auto_ptr and change the friend declaration to match. – Photon Dec 08 '14 at 12:30