Search code examples
c++templatesinheritancesingletonfriend

C++ Singleton template class inheritance


I have an abstract Singleton class. My goal is that any subclasses just have to implement the init() function AND NOTHING ELSE. Here is what I did:

template <typename T>
class Singleton
{
    public: 

        Singleton()
        {
            init();
        }

        static T& instance()
        {
            static T instance;
            return instance;
        }

    protected:
        virtual void init() = 0;   
};

class SubSingleton : public Singleton<SubSingleton>
{
    protected: 
        void init()
        {
            cout << "Init SubSingleton" << endl;
        }
};

This won't compile, since init() is protected and can't be called from a public static function. There are 2 solutions to this problem. First we can make the init() function public, but I don't want to expose this function publicly. So this only leaves the second solution, change the subclass as follows:

class SubSingleton : public Singleton<SubSingleton>
{
    friend class Singleton<SubSingleton>;

    protected:

        void init()
        {
            cout << "Init SubSingleton" << endl;
        }
};

This works perfectly, but I don't want the friend statement, since other programmers might extend my code and might not know that this should be added.

Is there any other way of implementing this without the friend statement? Maybe anything from Andrei Alexandrescu?

EDIT: The init function is now called in the constructor instead of the instance() function.

EDIT2: For technical reasons and compatibility I need an init() function and can't just do the initialization in the constructor.

The solution for casting works, but if I call init() from the constructor the casting doesn't work anymore. Any suggestions?


Solution

  • Problem is that you do not use the virtual function as you intend to use. i,e there no polymorphism in action now. Why? because you call init() on the direct derived object. The use of init() function being virtual is when you invoke init() either on the base-class reference or on base class pointer as given below. Then the invocation happens from the base-class scope and since instance() method is a base class method, calling a protected method from that is perfectly fine.

        static T& instance()
        {
            static T myInstance;
            Singleton<T>& t = myInstance;  // Just define a dummy reference here.
            t.init();
            return myInstance;
        }