【问题标题】:C++ Singleton inheritance issueC ++单例继承问题
【发布时间】:2018-06-10 17:11:54
【问题描述】:

我正在尝试为我的子类实现一个简单的继承单例模式。 因此,我正在实现一个父类,并且因为我想让其他人尽可能轻松地创建一个新的 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) 在构造函数中始终是“父亲” - 新的孩子();新的 Child2();应该被允许 - 新的孩子();新的孩子();不应该被允许 - 不应对子类进行任何修改

我知道我的 Singleton 实现可能看起来很奇怪。我乐于接受新想法。

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

【问题讨论】:

    标签: c++ oop inheritance singleton


    【解决方案1】:

    创建具有继承的类时,首先调用基类构造函数,然后调用层次结构中向上的子类。这意味着在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 个副本。它也是线程安全的,您无需担心清理。其他方法可以通过谷歌搜索找到。

    【讨论】:

    • 感谢您的回答!我知道这是正常的施工顺序。无论哪种方式,您能否为我提供一种替代方法来找出哪个子类称为父构造函数,而无需修改子类?如果没有,您能否提供另一个有效的替代方案?
    • @SergiuNistor 我用一种方法更新了答案。这不一定是最好的,但我发现它是一种相当干净的方式。
    • 再次感谢您的回答!尽管它并不像我想象的那样,但它是一个非常酷的实现。感谢您的努力!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-11
    • 2011-09-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-02
    相关资源
    最近更新 更多