我有一个抽象的Singleton类。我的目标是任何子类只需要实现init()函数和NOTHING ELSE。这是我做的:
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()受到保护,无法从公共静态函数调用。这个问题有两个解决方案。首先我们可以将init()函数设为public,但我不想公开公开这个函数。所以这只留下第二个解决方案,改变子类如下:
class SubSingleton : public Singleton<SubSingleton>
{
friend class Singleton<SubSingleton>;
protected:
void init()
{
cout << "Init SubSingleton" << endl;
}
};
这很好用,但我不想要友元声明,因为其他程序员可能会扩展我的代码,可能不知道应该添加它。
如果没有朋友声明,还有其他方法可以实现吗?也许Andrei Alexandrescu的一切?
编辑:现在在构造函数中调用init函数而不是instance()函数。
EDIT2:由于技术原因和兼容性,我需要一个init()函数,不能只在构造函数中进行初始化。
用于转换的解决方案可行,但如果我从构造函数中调用init(),则转换不再起作用。有什么建议吗?
答案 0 :(得分:3)
问题是您不打算使用虚拟功能。我现在没有多态行动了。为什么?因为你在直接派生对象上调用init()。使用init()函数是虚拟的是在基类引用或基类指针上调用init(),如下所示。然后调用从基类范围发生,因为instance()方法是基类方法,从中调用受保护的方法是完全正常的。
static T& instance()
{
static T myInstance;
Singleton<T>& t = myInstance; // Just define a dummy reference here.
t.init();
return myInstance;
}
答案 1 :(得分:3)
你根本不需要这个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()......
答案 2 :(得分:2)
似乎你混合了两种类型的polimorphysms:
1)如果你想静态调用SubSingleton::init()
,即使用CRTP,你不需要在基类中定义它 - 但是你真的必须让它可以被基类访问。
2)但是如果你将init()定义为虚拟,你使用动态的polimorphism,而不需要公开init()
:
static T& instance()
{
static T instance;
static_cast<Singleton<T> &>(instance).init();
return instance;
}