C ++ Singleton继承问题

时间:2018-06-10 17:11:54

标签: c++ oop inheritance singleton

我正在尝试为我的子类实现一个简单的继承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)总是&#34;父亲&#34;在构造函数内部 - 新孩子(); new Child2();应该被允许 - 新孩子();新孩子();不应该被允许 - 不应对子类进行任何修改

我知道我对Singleton的实现看起来很奇怪。我对新想法持开放态度。

我能够在JScript中实现这些想法,但在C ++中,我似乎无法找到使其工作的方法。

1 个答案:

答案 0 :(得分:4)

当创建具有继承的类时,首先调用基类构造函数,然后在子层次结构中向上调用子类。这意味着在Father的构造函数中,Child/Child2尚未构建。

在构造对象之前尝试使用该对象可能会导致未定义的行为。 C ++试图保护您免受此攻击。阅读例如the FAQ Lite。这不是完全相同的事情,但相关和阅读此内容可以让您了解为什么typeid会说对象是Father

cppreference我们可以阅读

  

如果在构造或销毁的对象上使用typeid(在析构函数或构造函数中,包括构造函数的初始化列表或默认成员初始值设定项),则此typeid引用的std :: type_info对象表示的类是正在建造或销毁,即使它不是最衍生的阶级。

我已经看到了几种实现单例的方法,最现代的似乎是返回对静态函数对象的引用。这是一个想法。

#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个副本。它也是线程安全的,你不需要担心清理。如果你谷歌可以找到其他方法。