这是从单身类派生的标准方法吗?

时间:2013-08-16 11:14:29

标签: c++ singleton

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)
    }
};

5 个答案:

答案 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();
}