【问题标题】:Why is the `int* Get()` called insted of `const int& Get()`?为什么将 `int* Get()` 称为 `const int& Get()` 的 insted?
【发布时间】:2018-05-24 00:26:54
【问题描述】:

我有一个类B,它有两种方法,一种返回指向成员变量的指针,另一种返回对变量的 const 引用。

我尝试调用这些方法。在调用期间,我将返回值存储到相应的返回类型中。

我期待适当的返回类型最终会调用适当的方法,但我收到一个编译错误:

错误:从“int*”到“int”的无效转换 [-fpermissive] const int& refval2 = b.Get(); `

这是我的代码:

#include <iostream>
class B{
public:
  int* Get(){
    return &x_;
  }
  const int & Get() const{
    return x_;
  }

private:
  int x_ = 0;
};

int main(){
  B b;
  const int& refval2 =  b.Get(); 
  int* pval2 =  b.Get(); 
}

【问题讨论】:

  • 选择要调用的重载函数时不使用返回类型。
  • 有没有办法确保调用正确的函数?
  • 根据 C++ 的规则,“正确”函数被调用,但返回类型错误。
  • 我将一个重命名为GetPtr(),而将另一个保留为Get

标签: c++ c++11 overload-resolution


【解决方案1】:

Return type is not part of function signatureoverload resolution 不考虑。

一般来说,参数与实参最接近的候选函数就是被调用的函数。

对于非静态成员函数调用,也涉及到被调用对象的类型。有两个Get(),一个是常量,一个是非常量。对于b.Get();,非常量Get() 是完全匹配的;要将 const Get() 称为对象 b,必须将其转换为 const。然后非常量的获胜,之后编译器将尝试将返回的int*转换为const int&amp;并失败。

所以

B b;
int* pval2 =  b.Get();          // call to non-const Get()

const B cb;
const int& refval2 =  cb.Get(); // call to const Get()

【讨论】:

  • 如果我可以问为什么在接收端是const int&amp; 时选择int* Get() 的规则是什么?
  • @codekaizer: b 是非常量,所以非常量 Get 总是被调用。 cb 是 const,所以总是调用 const Get。这取决于具有成员的类的类型,而不是返回值。
  • @MooingDuck,我同意。说得通。如果我可以问最后一个问题。我在标准的 over.loadover.match.best 部分中没有看到它。这是否在另一个部分中指定,其中匹配基于对象const-ness?
  • 好的,现在一切都说得通了。不过感谢@MooingDuck 提供的代码 sn-p。
【解决方案2】:

为什么int* Get() 被称为const int&amp; Get() 的insted?

const int & Get() const

const的成员函数。

来自class.this

如果成员函数声明为const,则this的类型为const X*

但是,您声明:

B b;

作为非const 将调用非const 函数int* Get()。因此,错误。

【讨论】:

    【解决方案3】:

    有两件事

    1. 重载决议中不考虑返回类型
    2. 在解决过载时会考虑方法的常量

    如果您在第二种方法中删除 const,编译器会报错。

    【讨论】:

      【解决方案4】:

      由于已经回答,不考虑返回类型。所以我看到了 3 种可能的解决方案:

      1 使其成为函数签名的一部分:

      class B {
      public:
         void Get( int *&refptr );
         void Get( int &refval ) const;
      };
      
      int main(){
        B b;
        int refval2 = 0;
        b.Get( refval2 ); 
        int* pval2 = nullptr;
        b.Get( pval2 ); 
      }
      

      但这会产生非常难看的代码,所以你最好使用方法 2 或 3 -

      2 使用不同的函数名,这很明显

      3 使用忽略参数:

      class B {
      public:
         int *Get( nullptr_t );
         const int &Get() const;
      };
      
      int main(){
        B b;
        const int &refval2 = b.Get();
        int* pval2 = b.Get( nullptr ); 
      }
      

      【讨论】:

      • 替代方案:代理返回对象:coliru.stacked-crooked.com/a/445c96a2e05c881b
      • @MooingDuck 这是你的主意,你应该提交自己的答案。
      • @Slava:哈哈我也这么想。提高了。 Mooing Duck:我发现 Proxy 类也很有趣。
      • @Slava:这是解决问题的替代方法,但与“为什么调用 int 而不是 const int?”没有直接关系。所以问题是关于为什么他会得到这些结果。
      【解决方案5】:

      问题在于编译器认为这两个 Get() 函数是相同的。如果您创建两个相同的函数,但返回类型不同,编译器将不知道您要使用哪个函数。要解决此问题,请更改一个或两个 Get() 函数的名称;比如说 GetXPtr() 和 GetX()。

      【讨论】:

      • 编译器其实知道要使用哪个函数,但不能因为返回类型错误。
      猜你喜欢
      • 2010-10-20
      • 1970-01-01
      • 2010-11-11
      • 2020-12-14
      相关资源
      最近更新 更多