在c++中,当常量也可以工作时,编译器为什么选择非常量函数
In c++, why does the compiler choose the non-const function when the const would work also?
例如,假设我有一个类:
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重载,那么在什么情况下它会调用非常量重载?
通过将a
强制转换为const Foo *
,可以使它使用另一个重载。
编辑:从C++注释
早些时候,在第2.5.11节中,概念的函数重载为介绍。在那里,它注意到该成员函数可能仅通过他们的const属性。在这些情况下,编译器将使用该成员函数与对象的const限定:
因为a不是常量指针。因此,非常量函数更接近匹配。以下是如何调用const函数:
const Foo* b = a;
std::string name = b->Name();
如果您同时有const和非常量重载,并且希望在非常量对象上调用const-one,这可能表明设计不好。
编译器在确定返回值时不考虑如何使用返回值;这不是规则的一部分。它不知道你是否在做
std::string name = b->Name();
或
b->Name() = "me";
它必须选择在这两种情况下都有效的版本。
您可以添加一个等效于"Name()const"的"cName"函数。通过这种方式,您可以调用函数的const版本,而无需首先转换为const对象。
这在C++0x中的新关键字auto中非常有用,这就是为什么他们更新库以包括cbegin()、cend()、crbegin()、crend(),以返回const_iterator,即使对象是非const。
您所做的可能更好的方法是使用setName()函数来更改名称,而不是返回对底层容器的引用,然后"可能"对其进行修改。
- 为什么我可以通过引用修改常量返回
- 为什么static_assert错误:即使我传递常量"expression must have a constant value"?
- 为什么C++在将一个对象复制到另一个对象时需要对这两个对象进行低级常量限定
- 为什么C++常量模板化向量在使用之前没有初始化?
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- 为什么常量方法可以采用非常量引用?
- 为什么我收到"从常量指针到指针的转换无效?
- 为什么当我们有常量引用时创建临时对象?
- 为什么 std::string_view 比常量字符*快?
- 为什么const_cast和static_cast常量引用没有效果?
- 为什么下面带有非常量转换函数的代码没有歧义?
- 模板推导:为什么函数指针模板定义在常量和/或引用时不匹配?
- 为什么乘以常量有符号整数分数没有优化?
- 为什么"具有常量成员的结构"类型的指针不能指向"具有非常量成员的结构"?
- 为什么在C++使用常量函数时常量是多余的?
- 为什么不能用常量表达式声明数组?
- 为什么我可以隐式地将字符*转换为常量字符*,但不能将无符号字符*
- 为什么在PIMPL中无法访问实现类的常量函数?
- 为什么C++中没有常量引用,就像常量指针一样?
- 为什么编译器在使用"无常量复制构造函数"时抱怨?