I'm playing with the idea of a singleton base class, but I'm having an issue with how to implement the GetInstance() function in the base class. Since I'm trying to make this ridiculously simple for the child, I'd like to handle that in the base.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class Singleton
{
private:
static Singleton* instance;
Singleton() { Construct(); } // Private to avoid other instances
protected:
virtualvoid Construct() = 0; ///< Initialization function used by children
public:
static Singleton* GetInstance()
{
if (instance == 0)
instance = new Singleton(); // Error! I want this to be a child class
return instance;
}
};
#include <string>
#include <iostream>
template <class T>
class Singleton
{
private:
static Singleton* instance;
protected:
Singleton() { Construct(); } // Private to avoid other instances
virtualvoid Construct() = 0; ///< Initialization function used by children
public:
static T* GetInstance()
{
if (instance == 0)
instance = new T(); // Error! I want this to be a child class
return instance;
}
};
Singleton* Singleton::instance = 0;
class Hello : public Singleton<Hello>
{
private:
std::string hello;
void Construct() { hello = "hello"; }
public:
std::string GetHello() const { return hello; }
};
int main()
{
std::cout << Hello::GetInstance()->GetHello();
}
||=== Build: Release in Test (compiler: GNU GCC Compiler) ===|
/home/stew/SVN/Test/Test/main.cpp|32|error: specializing member ‘Singleton<Hello>::instance’ requires ‘template<>’ syntax|
/home/stew/SVN/Test/Test/main.cpp||In instantiation of ‘static T* Singleton<T>::GetInstance() [with T = Hello]’:|
/home/stew/SVN/Test/Test/main.cpp|16|error: invalid conversion from ‘Singleton<Hello>*’ to ‘Hello*’ [-fpermissive]|
/home/stew/SVN/Test/Test/main.cpp||In instantiation of ‘Singleton<T>::Singleton() [with T = Hello]’:|
||=== Build failed: 2 error(s), 6 warning(s) (0 minute(s), 0 second(s)) ===|
||=== Run: Release in Test (compiler: GNU GCC Compiler) ===|
- line 7 should be static T* instance; (similar change on line 20 required). Either that, or static_cast instance to a T* on line 16.
- If the Child's ctor is private, the parent will need to be a friend in order to access it. Parents don't automatically have access to your private members. (EDIT: you weren't doing this.. nevermind)
- the virtual "Construct" member will not work because you cannot call virtual functions from a constructor or destructor (well you can... but it does not have the desired effect). Why are you bothering with this anyway? Why not just use a normal constructor? (EDIT: this actually makes more sense if you call construct after creating the object on line 16, rather than in the ctor. Though I would argue it should not be pure virtual.)
- Singletons are overrated and frequently overused. The only time I've ever really thought they were a good idea was for something like a resource manager... but even there it's debatable.
They also cause a lot of bloat, whenever Base<T>::instance() is called it has to do a check to see if it was initialized and it often inlines the constructor along with the check. It'd just be better to put it as a global object in a namespace.
I was making some global properties in my application. I thought a singleton would be nice to provide this information instead of passing it through a mess of constructors. A global instance would work, but I'd rather protect against multiple instances since there is no need for multiples.
A base-class is completely un-nessesary since I don't plan on using more than one, but I was trying it anyways to see how tough it would be.
I almost have it working thanks to the line 7 correction from Disch, but I'm having trouble calling the over-riden virtual function:
If virtualvoid Construct() is pure virtual, then I get undefined reference to 'Singleton<Hello>::Construct()'
If it is defined as below, I get no error, but Singleton<T>::Construct() is called instead of Hello::Construct().
I generally don't have any use for singletons though and actively try to avoid them.
Indeed. They're like global variables, in that they introduce unnecessary tight coupling within your code. And they're a pain in the ass when it comes to writing unit tests.
file s.h:
class MySingleton {
public:
void method1();
void method2();
void method3();
};
file s.cpp:
#include "s.h"
staticint member1; // statics instead of private singleton members.
staticint member2;
static string member3;
void MySingleton::method1()
{
cout << "Look at me! I'm all singly and stuff!\n";
}
// etc.
You're coding a singleton. Only it isn't a singleton because it's a base class. I mean a not a base class but a template..... So there's really more than one.... My head hurts already.
Step back. What are you trying to accomplish? What is the simplest way to do it? That's the way that you should choose. I have a feeling that you're over-complicating things.
dhayden, it's not a good idea to use static data members like that - they might not be initialized if other static data is being initialized based on your singleton.