C ++ Singleton类返回const引用

时间:2011-07-21 06:37:36

标签: c++

我有一个类如下定义的单例

class myData {
private:
    myData (void); // singleton class.
    // Copy and assignment is prohibted.
    myData (const myData &);
    myData & operator=(const myData &);
    static myData* s_pInstance;

public:
    ~myData (void);
    static const myData & Instance();
        static void Terminate();

    void myFunc() { cout << "my function..." ;}
};

//在cpp文件中。

myData* myData::s_pInstance(NULL);

myData::myData(){}

myData::~myData()
{
    s_pInstance = NULL;
}

const myData& myData::Instance()
{
    if (s_pInstance == NULL)
    {
        s_pInstance = new myData();
    }

    return *(s_pInstance); // want to avoid pointer as user may deallocate it, so i used const referense
}

void main() {

    (myData::Instance()).myFunc();

}

我收到以下错误

错误C2662:'myData :: myFunc':无法将'this'指针从'const myData'转换为'myData&amp;'

如何避免上述问题并从返回const引用的Instance函数调用函数?

谢谢!

4 个答案:

答案 0 :(得分:8)

您希望将func()声明为常量成员函数,因此编译器知道它不会违反instance()函数的常量返回值。

您也可以让instance()函数返回与const相关的“常规”引用。

所以要么转: void myFunc()进入void myFunc() const

或转: const myData& myData::Instance()进入myData& myData::Instance()

答案 1 :(得分:4)

如果要在const引用上调用函数,则调用的函数也必须是const,在您的情况下void myFunc() const

否则,如果效果更好,则可能会返回非const引用。

答案 2 :(得分:3)

该错误表明myData::Instance()是该类的const实例,并且无法在其上调用myFunc(),因为myFunc()可能会更改实例,而您不能更改const实例。

当然,你知道myFunc()无法真正改变实例,但你必须宣传这个事实,如下所示:

void myFunc() const { cout << "my function..." ;}

答案 3 :(得分:3)

避免整个讨论Singleton是否有一个好的模式或所有邪恶的来源,如果你实际上实现一个单身,很可能是const正确性不会像你期望的那样在那里工作,所以你应该知道一些陷阱。

首先你的错误:你的Instance()静态成员返回一个const引用,这意味着你只能执行不修改对象的操作,即标记为const的调用成员函数,或者使用公共成员如果以不修改其值的方式存在。我建议的解决方案是修改Instance()以返回非const引用,而不是像其他人建议的那样使func() const。


现在,当应用于您的特定Singleton问题时,通常可以更长时间地解释const-correctness问题。基本问题是当你实现一个类型时,你将那些修改对象的成员与那些不成功的成员分开,并将后者标记为const成员函数,以便编译器知道你的承诺(允许你在常量对象上调用该方法)并帮助您不要破坏它(如果您尝试修改方法定义中的状态,则会抱怨)。标记为const的方法可以应用于常量和非常量对象,但未标记为const的方法只能应用于不是const的对象

回到最初的代码段,如果你实现了一个单例,并且访问该对象的唯一方法是通过返回Instance()引用的const方法,那么你基本上限制了所有用户代码仅使用接口中实现的const方法。这意味着有效地要么所有方法都是非变异的,要么它们是无用的(永远不应该使用const_cast)。这反过来意味着如果你有任何非const操作,你想提供一个返回非const引用的Instance()方法。

您可以考虑实施Instance()的两个变体,但这不会真正有用。重载解析无助于用户代码确定使用哪个版本,因此您最终将采用不同的方法:Instance()ConstInstance()(选择您的姓名),这意味着它取决于用户用于确定使用哪一个的代码。小优势在于,在他们的代码中,访问器的选择将有助于记录他们的预期用途,甚至可能捕获一些错误,但更多时候他们只会调用非const版本,因为它可以工作