Singleton Inheritance - Which object is created?

78 Views Asked by At

I've created two classes - a base class and derived class where the base class is a singleton.

When I call the derived class constructor, which object is being created as the static instance? Is it a base class object or derived one, and why?

As

#include <iostream>
class Singleton {
protected:
    static Singleton* instance;
    Singleton() {}
public:
    static Singleton* getInstance() {
        if (!instance) {
            instance = new Singleton();
        }
        return instance;
    }
};
Singleton* Singleton::instance= nullptr;;

class DerivedSingleton : public Singleton {
public:
int x;
    static DerivedSingleton* getInstance() {
        if (!instance) {
            instance = new DerivedSingleton();
        }
        return (DerivedSingleton*)instance;
    }
};
int main(){
    Singleton *instance = DerivedSingleton::getInstance();
    std::cout << sizeof(DerivedSingleton) << std::endl;
    std::cout << sizeof(*instance) << std::endl;
    std::cout << sizeof(Singleton) << std::endl;
}

Output :

4
1
1

I tried printing the values of the sizes but i cant connect why the base class object is being created.

2

There are 2 best solutions below

2
GANESH JAGTAP On

Only one object is created, which is of type DerivedSingleton. This is because DerivedSingleton::getInstance() is called, and it ensures that only one instance of DerivedSingleton exists throughout the program.

0
463035818_is_not_an_ai On

Consider this simpler example:

#include <iostream>

struct foo {
    int a;
};

struct bar : foo {
    int b;
};

int main() {
    std::cout << sizeof(foo) << "\n";
    std::cout << sizeof(bar) << "\n";

    foo* f;
    bar* b;
    std::cout << sizeof(*f) << "\n";
    std::cout << sizeof(*b) << "\n";
}

Possible output is:

4
8
4
8

foo* f is a pointer to a foo. Dereferencing it yields a foo, not a bar. Hence, in your code sizeof(*instance) is effectively sizeof(Singleton).


Your Singleton design has various flaws.

Singleton can be copied:

Singleton a_copy = *Singleton::getInstance();
Singleton another_copy = a_copy;

DerivedSingleton has a public default constructor and can be copied too:

DerivedSingleton a;
DerivedSingleton b;
DerivedSingleton c = b;

And because the default constructor does not use Singleton::getInstance() but the protected constructor Singleton(), the two instances a and b each have their own distinct subobject of type Singleton. That's a whole lot of instances for something that should allow only one ;).

Live Demo

As mentioned in comments, things get worse when you use this with multiple threads, because your getInstance() is not thread-safe. You should read about the Meyer Singleton. It isn't the holy grail, though once you understood what it achieves and why you can still decide to use something else. For a base class that turns the derived into a singelton you can consider CRTP. Ordinary inheritance doesn't play that well with singleton-ness (merely making the constructor protected is not sufficient as illustrated with examples above).