例如,假设我有一个班级:
class Foo
{
public:
std::string& Name()
{
m_maybe_modified = true;
return m_name;
}
const std::string& Name() const
{
return m_name;
}
protected:
std::string m_name;
bool m_maybe_modified;
};
在代码的其他地方,我有类似的东西:
Foo *a;
// Do stuff...
std::string name = a->Name(); // <-- chooses the non-const version
有谁知道为什么编译器在这种情况下会选择非const版本?
这是一个有点人为的例子,但我们试图解决的实际问题是如果对象已经改变则定期自动保存,并且指针必须是非const的,因为它可能在某些时候被更改。
答案 0 :(得分:18)
因为a不是const指针。因此,非const函数是更接近的匹配。以下是调用const函数的方法:
const Foo* b = a;
std::string name = b->Name();
如果你同时拥有const和非const重载,并且想要在非const对象上调用const,那么这可能表明设计不好。
答案 1 :(得分:16)
我想到了两个答案:
非const版本更接近匹配。
如果它为非const情况调用const重载,那么它在什么情况下曾调用非const重载?
您可以通过将a
投射到const Foo *
来使用其他重载。
修改:来自C++ Annotations
早些时候,在第2.5.11节中概念 函数重载是 介绍。在那里它注意到该成员 函数可能仅仅被重载 他们的const属性。在那些情况下, 编译器将使用该成员 函数 匹配最紧密的 对象的const限定:
答案 2 :(得分:6)
编译器没有考虑如何在其确定中使用返回值;这不是规则的一部分。它不知道你是否在做
std::string name = b->Name();
或
b->Name() = "me";
必须选择适用于这两种情况的版本。
答案 3 :(得分:0)
您可以添加一个等同于“Name()const”的“cName”函数。这样,您可以调用函数的const版本,而无需首先转换为const对象。
这对于C ++ 0x中的new关键字auto来说非常有用,这就是为什么他们更新库以包含cbegin(),cend(),crbegin(),crend()来返回const_iterator的即使对象也是如此是非常数。
你正在做的事情可能更好,有一个setName()函数允许你更改名称,而不是返回对底层容器的引用,然后“可能”它被修改。