Truth is, singletons and inheritance do not play well together.
Yeah, yeah, the Singleton lovers and GoF cult will be all over me for this, saying "well, if you make your constructor protected..." and "you don't have to have a getInstance
method on the class, you can put it...", but they're just proving my point. Singletons have to jump through a number of hoops in order to be both a singleton and a base class.
But just to answer the question, say we have a singleton base class. It can even to some degree enforce its singleness through inheritance. (The constructor does one of the few things that can work when it can no longer be private: it throws an exception if another Base
already exists.) Say we also have a class Derived
that inherits from Base
. Since we're allowing inheritance, let's also say there can be any number of other subclasses of Base
, that may or may not inherit from Derived
.
But there's a problem -- the very one you're either already running into, or will soon. If we call Base::getInstance
without having constructed an object already, we'll get a null pointer. We'd like to get back whatever singleton object exists (it may be a Base
, and/or a Derived
, and/or an Other
). But it's hard to do so and still follow all the rules, cause there are only a couple of ways to do so -- and all of them have some drawbacks.
We could just create a Base
and return it. Screw Derived
and Other
. End result: Base::getInstance()
always returns exactly a Base
. The child classes never get to play. Kinda defeats the purpose, IMO.
We could put a getInstance
of our own in our derived class, and have the caller say Derived::getInstance()
if they specifically want a Derived
. This significantly increases coupling (because a caller now has to know to specifically request a Derived
, and ends up tying itself to that implementation).
We could do a variant of that last one -- but instead of getting the instance, the function just creates one. (While we're at it, let's rename the function to initInstance
, since we don't particularly care what it gets -- we're just calling it so that it creates a new Derived
and sets that as the One True Instance.)
So (barring any oddness unaccounted for yet), it works out kinda like this...
class Base {
static Base * theOneTrueInstance;
public:
static Base & getInstance() {
if (!theOneTrueInstance) initInstance();
return *theOneTrueInstance;
}
static void initInstance() { new Base; }
protected:
Base() {
if (theOneTrueInstance) throw std::logic_error("Instance already exists");
theOneTrueInstance = this;
}
virtual ~Base() { } // so random strangers can't delete me
};
Base* Base::theOneTrueInstance = 0;
class Derived : public Base {
public:
static void initInstance() {
new Derived; // Derived() calls Base(), which sets this as "the instance"
}
protected:
Derived() { } // so we can't be instantiated by outsiders
~Derived() { } // so random strangers can't delete me
};
And in your init code, you say Base::initInstance();
or Derived::initInstance();
, depending on which type you want the singleton to be. You'll have to cast the return value from Base::getInstance()
in order to use any Derived
-specific functions, of course, but without casting you can use any functions defined by Base
, including virtual functions overridden by Derived
.
Note that this way of doing it also has a number of drawbacks of its own, though:
It puts most of the burden of enforcing singleness on the base class. If the base doesn't have this or similar functionality, and you can't change it, you're kinda screwed.
The base class can't take all of the responsibility, though -- each class needs to declare a protected destructor, or someone could come along and delete the one instance after casting it (in)appropriately, and the whole thing goes to hell. What's worse, this can't be enforced by the compiler.
Because we're using protected destructors to prevent some random schmuck from deleting our instance, unless the compiler's smarter than i fear it is, even the runtime won't be able to properly delete your instance when the program ends. Bye bye, RAII...hello "memory leak detected" warnings. (Of course the memory will eventually be reclaimed by any decent OS. But if the destructor doesn't run, you can't depend on it to do cleanup for you. You'll need to call a cleanup function of some sort before you exit, and that won't give you anywhere near the same assurances that RAII can give you.)
It exposes an initInstance
method that, IMO, doesn't really belong in an API everyone can see. If you wanted, you could make initInstance
private and let your init function be a friend
, but then your class is making assumptions about code outside itself, and the coupling thing comes back into play.
Also note that the code above is not at all thread safe. If you need that, you're on your own.
Seriously, the less painful route is to forget trying to enforce singleness. The least complicated way to ensure that there's only one instance is to only create one. If you need to use it multiple places, consider dependency injection. (The non-framework version of that amounts to "pass the object to stuff that needs it". :P ) I went and designed the above stuff just to try and prove myself wrong about singletons and inheritance, and just reaffirmed to myself how evil the combination is. I wouldn't recommend ever actually doing it in real code.