12

Recently I got question on implement Singleton but abstract base class involved. Suppose we have class hierarchy like this:

class IFoo {...}; // it's ABC
class Foo : public IFoo {...};

we have singleton class defined as follows:

template <typename T>
class Singleton
{
public:
static T* Instance() {
   if (m_instance == NULL) {
      m_instance = new T();
   }
   return m_instance;
}
private:
static T* m_instance;
};

So if I want to use like following: IFoo::Instance()->foo(); what should I do?

If I do this: class IFoo : public Singleton<IFoo> {...}; it won't work since Singleton will call IFoo's ctor but IFoo is a ABC so can not be created.

And this: class Foo : public IFoo, public Singleton<Foo> {...}; can't work too, because this way class IFoo doesn't have the interface for method Instance(), so the call IFoo::Instance() will fail.

Any ideas?

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • can you please format the code – RvdK Jul 07 '09 at 09:46
  • 3
    Please don't use this singelton pattern. It is the classic anti-pattern for singelton implementation as it is hard to correctly destroy the instance. http://stackoverflow.com/questions/86582/singleton-how-should-it-be-used – Martin York Jul 07 '09 at 15:30
  • 4
    A great discussion on how to implement a singleton, along with thread-safety in C++ can be found in this paper: http://www.aristeia.com/Papers/DDJ%5FJul%5FAug%5F2004%5Frevised.pdf –  Oct 30 '09 at 11:35

9 Answers9

10

You'd want to use something like

IFoo my_foo = Singleton<Foo>::Instance();
my_foo->foo();

Basically you'll have to instantiate the template Singleton using a concrete class (in this case, your class Foo) and given that your Foo derives from IFoo you can refer to it through a base pointer. You cannot directly instantiate a template using an incomplete or abstract class.

Timo Geusch
  • 24,095
  • 5
  • 52
  • 70
8

You can't do this. IFoo is an interface, by design and definition. The number of instances is therefore 0. On the other hand, the definition of a singleton class is that you have 1 instance. 0 != 1.

MSalters
  • 173,980
  • 10
  • 155
  • 350
2

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;
}
rtn
  • 127,556
  • 20
  • 111
  • 121
1

The annoying meta-answer is, "why are you using a singleton?" I have yet to find a situation where you really need to use it. IMHO its drawbacks outweigh its advantages, in real life situations that is.

Using something like 'boost::noncopyable' might be what you are after.

See this post for more info

Community
  • 1
  • 1
Chris Huang-Leaver
  • 6,059
  • 6
  • 41
  • 67
  • 3
    I agree with your point. But you still need to learn how to do it (and do it correctly) just so you know the problems it adds (tight coupling). – Martin York Jul 07 '09 at 15:32
1

Here is another possible solution I found 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 the abstract class is in a header, while 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 these additions, you can now do the following:

IFoo::Instance( BuildFoo );

IFoo::Instance()->SomeFunc();

Just remember to #define ABSTRACT_CLASS in the header for every abstract class.

jmclaine
  • 23
  • 6
1

I've encountered the same problem recently.

It can be implemented with what I know as gem singleton. It using assert for forcing uniqueness and Curiously recurring template pattern for calling interface implementation 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 FooImpl, call of IFoo::getSingleton().foo() will call FooImpl's code.

int main() {
  FooImpl f;
  IFoo::getSingleton().foo();
}

demo

pergy
  • 5,285
  • 1
  • 22
  • 36
0

Look at it like this: There is nothing in your program that would tell the compiler which implementation of the IFoo interface it should be instantiating. Remember, there could be other implementations besides Foo.

If you want to use a class via an interface and define which actual implementation shall be used somewhere else, take a look at the Abstract Factory pattern.

Jan
  • 2,480
  • 2
  • 17
  • 19
0

I had to do something similar to add unit tests to some legacy code. I had to replace an existing singleton which used a template. I gave two parameters to the singleton template, the first is the interface the second is the implementation.

However I also had to add a setTestInstance method to enable the unit tests override 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 use a std::auto_ptr and m_instance should be a boost::scoped_ptr. To avoid memory leaks.

iain
  • 10,798
  • 3
  • 37
  • 41
0

I think the best solution would be to introduce a factory class or method here. Just imagine 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

ovanes
  • 5,483
  • 2
  • 34
  • 60