【问题标题】:Why does non-const method hide const overload?为什么非 const 方法隐藏 const 重载?
【发布时间】:2015-03-05 13:26:59
【问题描述】:

给定以下代码:

class A
{
public:
    A(): value( 0 ) {}

    int* get()
    {
        return &value;
    }

    const int& get() const
    {
        return value;
    }

private:
    int value;
};

int main()
{
    A a;
    const int& ref_value = a.get();
}

导致以下编译错误:

prog.cpp: In function 'int main()':
prog.cpp:23:35: error: invalid conversion from 'int*' to 'int'
      const int& ref_value = a.get();
                                   ^

似乎带有 const 修饰符的重载 get() 方法确实被完全忽略了,编译器只看到它的非常量定义。这是可以理解的,因为 a 对象不是恒定的。一种解决方案是使 a 对象保持不变。尽管还有其他两种使代码可编译的解决方案:

  1. 更改 const get() 方法的签名通过不同的名称或其他添加的参数。

    int* get();
    const int& get_changed() const; <-- this gets called
    
  2. 更改非常量 get() 方法以返回引用而不是指针。

    int& get(); <-- this gets called
    const int& get() const; 
    

虽然有

int* get();
const int& get() const;

我们有一个编译器错误。

令我困惑的是所有这些行为背后的原因。

【问题讨论】:

  • 为什么会令人费解?如果在非常量对象上调用const 方法,会不会更加令人费解?
  • 是的,这恰好发生在我提到的那两种情况下(const 方法在非常量对象上被调用),所以它仍然令人费解。
  • 如果只有一个 const 方法,则不需要执行重载决议。只能调用 const 方法。如果有两个重载,则为非常量对象选择非常量,反之亦然。我并不觉得这特别令人费解。
  • 为什么会出现编译错误?为什么不为非常量对象选择 const 方法而不是给出编译错误?
  • 在 SO 中搜索一些信息,我发现其基本原理与 C++ 的强类型有关。让返回类型成为函数签名的一部分有效地使返回值的隐式/显式转换成为一场灾难。就像这里的评论一样,如果返回值被丢弃怎么办? stackoverflow.com/questions/9568852/overloading-by-return-type

标签: c++ reference overriding constants


【解决方案1】:

当您同时拥有具有相同参数的同一函数的const 和非const 重载时,调用哪个函数取决于上对象的constness您正在调用该函数。所以调用非 const a 必须调用非 const 重载。

和这个完全一样的情况:

void foo(int *p);

void foo(const int *p);


int main()
{
  int i;
  const int ci;
  foo(&i);  // Calls the first overload
  foo(&ci);  // Calls the second overload
}

const-qualified 函数可以在非const-qualified 对象上调用,但这需要“非常量到常量”的转换。如果存在不需要这种转换的重载(更好的匹配),它将是首选。

【讨论】:

  • 通过“参数”,您刚刚排除了返回类型作为签名的一部分。
  • @user3528438 签名不包括返回类型。至少对于非模板。
  • @user3528438 这是正确的(因为我从未提到“签名”这个词)。重载解析根本不看返回类型。
  • @juanchopanza 但在 OP 中,更改“int* get();”到“int&get();”解决问题。这样做有什么原因吗?
  • @user3528438 因为它然后调用非常量重载并将返回的int&amp; 绑定到const int&amp; ref_value
【解决方案2】:

原因是编译器无法根据不同的返回类型进行重载解析。

重载解析只考虑函数签名。并且函数签名仅由函数名、参数和 cv 限定符组成 - 而不是返回类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-08
    • 2018-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多