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

时间:2020-03-06 15:02:41  来源:igfitidea点击:

例如,假设我有一个课:

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版本是更接近的匹配。
  • 如果在非const情况下调用了const重载,那么在什么情况下会调用非const重载?

我们可以通过将a强制转换为const Foo *来使用其他重载。

编辑:从C ++批注

Earlier, in section 2.5.11 the concept
  of function overloading was
  introduced. There it noted that member
  functions may be overloaded merely by
  their const attribute. In those cases,
  the compiler will use the member
  function matching most closely the
  const-qualification of the object:

因为a不是const指针。因此,非const函数是更紧密的匹配。这是调用const函数的方法:

const Foo* b = a;
std::string name = b->Name();

如果我们同时具有const和非const重载,并且想在非const对象上调用const,则可能表明设计不良。

编译器在确定时不考虑我们如何使用返回值;那不是规则的一部分。不知道你在做什么

std::string name = b->Name();

或者

b->Name() = "me";

它必须选择在两种情况下均适用的版本。

我们可以添加一个等效于" Name()const"的" cName"函数。这样,我们可以调用函数的const版本,而无需先强制转换为const对象。

这在C ++ 0x中使用new关键字auto最为有用,这就是为什么他们将库更新为包含cbegin(),cend(),crbegin(),crend()以返回const_iterator的原因,即使该对象不是const。

通过使用setName()函数可以更好地完成工作,该函数允许我们更改名称而不是返回对基础容器的引用,然后"也许"对其进行修改。