Vapire
Vapire

Reputation: 4578

C++ template singleton base class for deep level inheritance

So I have a simple singleton template base class (minified for question purposes):

template <typename T>
class Singleton {
public:
    static T& instance() {
        static T me;
        return me;
    }
};

Now I want to have a "Base class that's a singleton":

class Base : public Singleton<Base> {
public:
    void print() { std::cout << &instance() << std::endl; }
}

What I want now is deriving children classes from this base class, which are their own singletons:

class A : public Base {
    // ...
}

class B : public Base {
    // ...
}

Of course if I do this

A::instance().print();
B::instance().print();

I get the same address in both cases. Is there a way to accomplish this?

In case you're wondering what for: I want to program a ResourceManager base class which is being inherited by a class ImageManager, a class 'AudioManager', etc. And I'd like them not to share actually the same instance, but still having only one instance per manager...

Upvotes: 0

Views: 2567

Answers (3)

Puppy
Puppy

Reputation: 146968

You will have to make Base a template and pass that to Singleton, then inherit from Base<A> if you wish to achieve this. Or, if you want Base to be a Singleton and A/B to be a Singleton, then they will have to inherit from Singleton<A>, Singleton<B> in addition to Base.

But dear lord, man, Singletons are a curse on you and your children for a hundred generations. Why would you do that to yourself?

Upvotes: 6

BigBoss
BigBoss

Reputation: 6914

The best solution that I see for when a base class must have something from its child is using Child as an argument to Base as follow:

template< bool val, class TrueT, class FlaseT >
struct If {
    typedef TrueT type;
};
template< class TrueT, class FalseT >
struct If< false, TrueT, FalseT > {
    typedef FalseT type;
};
template< class DerivedT = void >
class Base {
public:
    typedef typename If<std::is_same<DerivedT, void>::value,
        Base<DerivedT>, DerivedT>::type this_type;
    static this_type& instance() {
        this_type me;
        return me;
    }

public:
    void test() {}
};
class A : public Base<A> {
public:
    void print() {}
};
class B : public Base<B> {
public:
    void print() {}
};
Base<>::instance().test();
B::instance().print();
A::instance().print();

Upvotes: 1

earl3s
earl3s

Reputation: 2373

My suggestion would be to make Base a non singleton class and then make Class A and Class B singletons that instantiate the Base class. This gives you flexibility and follows the object oriented principle of favoring composition over inheritance http://www.artima.com/lejava/articles/designprinciples4.html

Because of the static members required on a Singleton you cannot directly inherit from a Singleton Class. Composition will serve you better in this situation, and most others as well.

Upvotes: 1

Related Questions