C++Singleton类返回常量引用

C++ Singleton class returning const reference

本文关键字:引用 常量 返回 C++Singleton      更新时间:2023-10-16

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

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&">

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

谢谢!

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

相反,您也可以使instance()函数返回一个与const函数相同的"正则"引用。

因此,请转向:void myFunc()转化为void myFunc() const

或者转向:const myData& myData::Instance()转换为myData& myData::Instance()

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

否则,如果效果更好的话,您可能会返回一个非常量引用。

错误表明myData::Instance()是该类的常量实例,它不能在此调用myFunc(),因为myFunc()可能会更改实例,而您不能更改常量实例。

当然,您知道myFunc()不能真正更改实例,但您必须宣传这一事实,如下所示:

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

避免讨论Singleton是一个好的模式还是万恶之源,如果你真的在实现Singleton,那么const正确性很可能不会像你预期的那样工作,所以你应该意识到一些陷阱。

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


现在,当应用于特定的Singleton问题时,对一般的常量正确性问题进行更长的解释。基本问题是,当你实现一个类型时,你将那些修改对象的成员和那些不修改的成员分开,并将后者标记为const成员函数,这样编译器就知道你的承诺(允许你在常量对象上调用该方法(,并帮助你不破坏它(如果你试图修改方法定义中的状态,就会抱怨(。标记为const的方法既可以应用于常量对象,也可以应用于非常量对象,但未标记为const的方法只能应用于非const的对象。

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

您可以考虑实现Instance()的两个变体,但这并没有真正的帮助。重载解决方案无助于用户代码确定使用哪个版本,因此您最终将不得不使用不同的方法:Instance()ConstInstance()(选择您的名称(,这意味着由用户代码决定使用哪个版本。小的优点是,在他们的代码中,访问器的选择将有助于记录他们的预期用途,甚至可能会发现一些错误,但通常情况下,他们只会调用非常量版本,因为它有效