1

我的基类是具有受保护 c'tor 的单例。现在,我可以从中派生另一个类,但我无法在派生类的函数中创建该基类的实例。根据我的设计,这是预期的行为。但我想知道 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)
    }
};
4

5 回答 5

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().

于 2013-08-16T12:14:34.990 回答
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; }

并成为拥有私人 ctor / dtorinstance_of<yourclass>()的朋友。yourclass

静态变量的使用使授予的对象可以正确构造和销毁。(与剩余的泄露指针不同,没有析构函数调用......)

于 2013-08-16T12:33:52.607 回答
0

这是预期的行为。Deringlton规则是,如果指针类型为 ,您只能访问受保护的成员Deringlton。您不能通过类型的指针访问受保护的成员Singleton。例如:

Deringlton* d = this;
d->someProtectedMethod(); // OK!
Singleton* s = this;
s->someProtectedMethod(); // Will fail

由于new Singleton不是通过Deringlton指针访问,所以不允许。您只能通过 Deringlton 访问它new Deringlton

于 2013-08-16T11:24:24.153 回答
0

如果你必须做一个单例(你应该避免)实例和(!)声明是一个单例。您可以使用具有“通用”模板的模板,但继承并不好。

于 2013-08-16T11:24:56.190 回答
0

此行为在标准中指定。

C++11 的第 11.4 节 [class.protected] 状态(强调我的):

如前所述,授予对protected成员的访问权限是因为引用发生在某个类的朋友或成员中C。如果访问要形成指向成员的指针(5.3.1),则嵌套名称说明符应表示 C 或从 C 派生的类。所有其他访问都涉及(可能是隐式的)对象表达式(5.2.5)。在这种情况下,对象表达式的类应该是C 或派生自的类C

这意味着只有在创建派生类的对象时才授予对基构造函数的访问权。例如,这将编译:

Deringlton()
{
    Deringlton* p = new Deringlton();
}
于 2013-08-16T11:25:00.817 回答