[ACCEPTED]-Singleton and Abstract base class in C++-singleton
You'd want to use something like
IFoo my_foo = Singleton<Foo>::Instance();
my_foo->foo();
Basically 7 you'll have to instantiate the template 6 Singleton using a concrete class (in this 5 case, your class Foo) and given that your 4 Foo derives from IFoo you can refer to it 3 through a base pointer. You cannot directly 2 instantiate a template using an incomplete 1 or abstract class.
You can't do this. IFoo is an interface, by 4 design and definition. The number of instances 3 is therefore 0. On the other hand, the definition 2 of a singleton class is that you have 1 1 instance. 0 != 1.
You can always do something like this:
class IFoo {};
class Foo : public IFoo {};
template <typename T>
class Singleton
{
// ..
};
typedef Singleton<Foo> FooSingleton;
int main()
{
FooSingleton::Instance()->foo();
return 0;
}
0
The annoying meta-answer is, "why are 6 you using a singleton?" I have yet 5 to find a situation where you really need to use 4 it. IMHO its drawbacks outweigh its advantages, in 3 real life situations that is.
Using something 2 like 'boost::noncopyable' might be what 1 you are after.
Here is another possible solution I found 6 that works nicely.
Add this to Singleton:
#ifndef ABSTRACT_CLASS
static T* D()
{
return new T();
}
#else
static T* D()
{
return NULL;
}
#endif
static T* Instance( T*(*func)() )
{
if( !m_instance )
{
m_instance = func();
}
return m_instance;
}
static T* Instance()
{
if( !m_instance )
{
m_instance = D();
}
return m_instance;
}
Ensure 5 the abstract class is in a header, while 4 the implementations are in sources.
For example:
// IFoo.h
//
#define ABSTRACT_CLASS
class IFoo
{
virtual ~IFoo() {}
virtual void SomeFunc() = 0;
};
extern IFoo* BuildFoo();
// Foo.cpp
//
#include "IFoo.h"
class Foo : public IFoo
{
Foo() {}
~Foo() {}
void SomeFunc() {}
};
IFoo* BuildFoo() { return new Foo(); }
With 3 these additions, you can now do the following:
IFoo::Instance( BuildFoo );
IFoo::Instance()->SomeFunc();
Just 2 remember to #define ABSTRACT_CLASS in the 1 header for every abstract class.
I've encountered the same problem recently.
It can be implemented with 4 what I know as gem singleton. It using assert
for forcing uniqueness 3 and Curiously recurring template pattern for calling interface implementation 2 via singleton:
template <typename T>
class Singleton {
public:
Singleton(const Singleton<T>&) = delete;
Singleton& operator=(const Singleton<T>&) = delete;
Singleton() {
assert(!msSingleton);
msSingleton = static_cast<T*>(this);
}
~Singleton(void) {
assert(msSingleton);
msSingleton = 0;
}
static T& getSingleton(void) {
assert(msSingleton);
return (*msSingleton);
}
protected:
static T* msSingleton;
};
class IFoo : public Singleton<IFoo> {
public:
virtual void foo() = 0;
};
class FooImpl : public IFoo {
public:
FooImpl();
void foo() override { std::cout << "FooImpl::foo()\n"; }
};
template <>
IFoo* Singleton<IFoo>::msSingleton = 0;
FooImpl::FooImpl() { msSingleton = this; }
After manually instantiating 1 FooImpl
, call of IFoo::getSingleton().foo()
will call FooImpl
's code.
int main() {
FooImpl f;
IFoo::getSingleton().foo();
}
Look at it like this: There is nothing in 8 your program that would tell the compiler 7 which implementation of the IFoo interface 6 it should be instantiating. Remember, there 5 could be other implementations besides Foo.
If 4 you want to use a class via an interface 3 and define which actual implementation shall 2 be used somewhere else, take a look at the 1 Abstract Factory pattern.
I had to do something similar to add unit 9 tests to some legacy code. I had to replace 8 an existing singleton which used a template. I 7 gave two parameters to the singleton template, the 6 first is the interface the second is the 5 implementation.
However I also had to add 4 a setTestInstance
method to enable the unit tests override 3 the instance at runtime.
template <typename IfaceT, typename ImplT>
class Singleton
{
public:
static IfaceT* Instance() {
if (m_instance == NULL) {
m_instance = new ImplT();
}
return m_instance;
}
// Only used for unit tests
// Takes ownership of instance
static void setTestInstance(IfaceT* instace) {
m_instance = instance;
}
private:
static IfaceT * m_instance;
};
In this case setTestInstance
should 2 use a std::auto_ptr
and m_instance
should be a boost::scoped_ptr
. To avoid memory 1 leaks.
I think the best solution would be to introduce 2 a factory class or method here. Just imagine 1 the following:
struct FooCreator
{
typedef IFoo* result_type;
result_type operator()()const
{
return new Foo;
}
};
template<class Factory>
struct Singleton
{
static typename Factory::result_type instance()
{
if(instance_==typename Factory::result_type())
instance_ = Factory()();
return instance_;
}
private:
Singleton(){};
static typename Factory::result_type instance_;
};
template<class F>
typename F::result_type Singleton<F>::instance_ = typename F::result_type();
Best Regards,
Ovanes
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.