My Base类是具有受保护c'tor的Singleton。现在,我可以从中派生另一个类,但我不能在派生类的函数内创建该Base类的实例。根据我的设计,这是预期的行为。但我想知道C ++标准或我的编译器特定行为是否正确? (因此,如果我希望将来移植此代码,我不应该遇到问题)
class Singleton
{
protected:
Singleton() {}
public:
Singleton * GetInstance()
{
static Singleton* InstanceCreated = NULL ;
if (!InstanceCreated)
InstanceCreated = new Singleton ;
return InstanceCreated ;
}
};
class Deringlton : public Singleton
{
public:
Deringlton()
{
Singleton * pSing ;
// pSing = new Singlton ; // Cannot create object of singlton
// (Despite class is derived from singlton)
}
};
答案 0 :(得分:4)
我认为提供通用单例实现的更好方法是使用CRTP并直接从该模板继承。这意味着每个类自动实现仅从CRTP基础继承的单例模式:
template<typename DERIVED>
class generic_singleton
{
private:
static DERIVED* _instance;
static void _singleton_deleter() { delete _instance; } //Function that manages the destruction of the instance at the end of the execution.
protected:
generic_singleton() {}
virtual ~generic_singleton() {} //IMPORTANT: virtual destructor
public:
DERIVED& instance() //Never return pointers!!! Be aware of "delete Foo.instance()"
{
if(!_instance)
{
_instance = new DERIVED;
std::atexit( _singleton_deleter ); //Destruction of instance registered at runtime exit (No leak).
}
return static_cast<DERIVED&>( _instance );
}
};
template<typename DERIVED>
DERIVED* generic_singleton<DERIVED>::_instance = nullptr;
通过使用std::ateexit()
注册在应用程序末尾执行删除的功能来提供内存释放。
答案 1 :(得分:1)
指针不仅仅是一个静态变量是什么意思?
class Singleton
{
public:
static Singleton& instance()
{ static Singleton z; return z; }
private:
Singleton() {}
~SIngleton() {}
};
没有看到任何推导它的价值。
如果您想将此模式编码为模板,则可以执行
template<class S>
S& instance_of() { static S z; return z; }
并instance_of<yourclass>()
成为yourclass
的朋友,拥有私人ctor / dtor。
使用静态变量可以正确构造和销毁授予的对象。 (与剩余的泄漏指针不同,没有析构函数调用...)
答案 2 :(得分:0)
这是预期的行为。规则是,如果指针的类型为Deringlton
,则只能访问Deringlton
中的受保护成员。您无法通过类型为Singleton
的指针访问受保护的成员。例如:
Deringlton* d = this;
d->someProtectedMethod(); // OK!
Singleton* s = this;
s->someProtectedMethod(); // Will fail
由于访问new Singleton
不是通过Deringlton
指针,因此不允许。您只能通过new Deringlton
通过Deringlton访问它。
答案 3 :(得分:0)
如果你必须制作一个单例(你应该避免)实例和(!)声明是一个单例。你可以使用一个'泛型'模板,但继承是不行的。
答案 4 :(得分:0)
此行为在标准中指定。
第11.4节[class.protected]的C ++ 11状态(强调我的):
如前所述,授予对
的类protected
成员的访问权限,因为 引用发生在某个类C
的朋友或成员中。如果 access是形成一个指向成员(5.3.1)的指针 nested-name-specifier应表示C或从C派生的类。 All 其他访问涉及(可能是隐式的)对象表达式 (5.2.5)。在这种情况下,对象表达式的类应为C
或者来自C
。
这意味着只有在创建派生类的对象时,才会授予对基本构造函数的访问权限。例如,这将编译:
Deringlton()
{
Deringlton* p = new Deringlton();
}