我有一个类如下定义的单例
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函数调用函数?
谢谢!
答案 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版本,因为它可以工作