Проблема наследования синглтона в C ++ - PullRequest
0 голосов
/ 10 июня 2018

Я пытаюсь реализовать простой унаследованный шаблон Singleton для моих дочерних классов.Поэтому я реализую родительский класс, и, поскольку я хочу максимально упростить создание нового дочернего класса Singleton, мне нужно обработать внутри конструктора родительского класса все операции, необходимые для реализации Singleton для дочернего элемента.классы.

#include <vector>
#include <typeinfo>
#include <iostream>

class Father
{
protected:
    Father()
    {
        for(auto & instance : Father::singletonInstances)
            if(typeid(instance) == typeid(this))    //    typeid(this) will always be "Father", which is actually the issue
            {
                //  Singleton instance already exists for this class
                * this = instance;
                std::cout<<"An instance of the given class is already active\n";

                return;
            }

        std::cout<<"Constructed\n";

        //  Otherwise, mark this as the Singleton instance for this class
        Father::singletonInstances.emplace_back(this);
    }
public:
    Father operator=(Father * inputObj) { return * inputObj; }
private:
    static std::vector<Father *> singletonInstances;
};

std::vector<Father *> Father::singletonInstances;

class Child : protected Father
{
public:
    Child() : Father() {}
};

class Child2 : protected Father
{
public:
    Child2() : Father() {}
};

int main()
{
    new Child();
    new Child2();

    return 0;
}

Вывод:

Constructed
An instance of the given class is already active

Итак, чтобы прояснить ситуацию еще раз: - Проблема в том, что typeid (this) всегда является "Father" внутри конструктора - new Child();новый Child2 ();должно быть разрешено - new Child ();новый ребенок ();не должно быть разрешено - не следует вносить изменения в дочерние классы

Я знаю, что моя реализация Singleton может выглядеть довольно странно.Я открыт для новых идей.

Мне удалось реализовать эти идеи в JScript, однако в C ++ я не могу найти способ заставить его работать.

1 Ответ

0 голосов
/ 10 июня 2018

Когда создается класс с наследованием, сначала вызывается конструктор базового класса, после чего дочерние классы поднимаются вверх в иерархии.Это означает, что в конструкторе Father, Child/Child2 еще не создан.

Попытка использовать объект до того, как он будет создан, вероятно, приведет к неопределенному поведению.C ++ пытается защитить вас от этого.Прочитайте например FAQ Lite .Это не совсем то же самое, но это связано, и чтение этого должно дать вам представление, почему typeid сказал бы, что объект является Father.

В cppreference , который мы можем прочитать

Если typeid используется на строящемся или разрушаемом объекте (в деструкторе или в конструкторе, включая список инициализатора конструктора или инициализаторы членов по умолчанию), то объект std :: type_info, на который ссылается этотtypeid представляет класс, который создается или уничтожается, даже если он не является самым производным классом.

Я видел несколько способов реализации синглетонов, самый современный из них, кажется, возвращает ссылку наобъект статической функции.Вот одна из идей.

#include <iostream>

template <typename T>
T& Singleton() {
    static T single;
    return single;
}

class Foo {
    private:
    Foo() {
        std::cout << "Constructed" << std::endl;
    }

    friend Foo& Singleton<Foo>();

    public:
    void print() {
        std::cout << "Foo" << std::endl;
    }
};

int main() {
    //Foo f; not allowed
    Singleton<Foo>().print();
    Singleton<Foo>().print();
}

Для этого требуется, чтобы каждый экземпляр-одиночка имел закрытый конструктор и friend экземпляр шаблона.Только функция Singleton позволит создать Foo, и она будет создавать только 1 копию.Это также потокобезопасно, и вам не нужно беспокоиться об очистке.Другие подходы можно найти, если вы гуглите вокруг.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...