5

我有一个抽象的单例类。我的目标是任何子类只需要实现 init() 函数就可以了。这是我所做的:

template <typename T>
class Singleton
{
    public: 

        Singleton()
        {
            init();
        }

        static T& instance()
        {
            static T instance;
            return instance;
        }

    protected:
        virtual void init() = 0;   
};

class SubSingleton : public Singleton<SubSingleton>
{
    protected: 
        void init()
        {
            cout << "Init SubSingleton" << endl;
        }
};

这不会编译,因为 init() 受保护并且不能从公共静态函数调用。这个问题有2个解决方案。首先我们可以公开 init() 函数,但我不想公开这个函数。所以这只剩下第二种解决方案,改变子类如下:

class SubSingleton : public Singleton<SubSingleton>
{
    friend class Singleton<SubSingleton>;

    protected:

        void init()
        {
            cout << "Init SubSingleton" << endl;
        }
};

这完美地工作,但我不想要朋友声明,因为其他程序员可能会扩展我的代码并且可能不知道应该添加它。

如果没有朋友声明,还有其他方法可以实现吗?也许安德烈亚历山德雷斯库的任何东西?

编辑:现在在构造函数中调用 init 函数而不是 instance() 函数。

EDIT2:出于技术原因和兼容性,我需要一个 init() 函数,不能只在构造函数中进行初始化。

转换的解决方案有效,但如果我从构造函数调用 init() ,则转换不再起作用。有什么建议么?

4

3 回答 3

4

你根本不需要这个 init() 东西。它只会在这里制造问题。

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

class SubSingleton : public Singleton<SubSingleton>
{
    public: 
        SubSingleton()
        {
            cout << "Init SubSingleton" << endl;
        }
};

通过这种方式,您不仅可以删除不必要的东西 - 而且您还可以防止每次有人调用 instanse() 时调用 init()...

于 2012-07-08T10:49:03.147 回答
3

问题是您没有使用您打算使用的虚拟功能。i,e 现在没有多态性在起作用。为什么?因为您在直接派生对象上调用 init() 。当您在基类引用或基类指针上调用 init() 时,init() 函数的使用是虚拟的,如下所示。然后调用发生在基类范围内,并且由于 instance() 方法是基类方法,因此调用受保护的方法非常好。

    static T& instance()
    {
        static T myInstance;
        Singleton<T>& t = myInstance;  // Just define a dummy reference here.
        t.init();
        return myInstance;
    }
于 2012-07-08T09:37:43.463 回答
2

您似乎混合了两种类型的多态性:

1)如果你想SubSingleton::init()“静态”调用,即使用CRTP,你不需要在基类中定义它——但是你真的必须让它可以被基类访问。

2)但是如果你定义 init() 为 virtual,你使用动态多态,并且不需要init()公开:

static T& instance() 
{ 
  static T instance; 
  static_cast<Singleton<T> &>(instance).init(); 
  return instance; 
} 
于 2012-07-08T08:58:42.333 回答