在c++中,当常量也可以工作时,编译器为什么选择非常量函数

In c++, why does the compiler choose the non-const function when the const would work also?

本文关键字:常量 为什么 编译器 函数 选择 非常 也可以 c++ 工作      更新时间:2023-10-16

例如,假设我有一个类:

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

有人知道为什么编译器在这种情况下会选择非常量版本吗?

这是一个有点做作的例子,但我们试图解决的实际问题是,如果对象发生了更改,则会定期自动保存对象,并且指针必须是非常量,因为它可能会在某个时刻发生更改。

脑海中浮现出两个答案:

  1. 非常量版本更接近。

  2. 如果它为非常量情况调用了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()函数来更改名称,而不是返回对底层容器的引用,然后"可能"对其进行修改。