在函数声明末尾使用“const”重载

Overloading with “const” at end of function declaration

我有 3 次尝试重载函数 "begin()"

class Test
{
public:

    //case 1: compiler error
    int begin();
    const int begin();

    //case 2:compiler warning: type qualifiers ignored on function return type
    int begin();
    const int begin() const;

    //case 3: ok
    int begin();
    int begin() const;
};

对于构建成功的两种情况,编译器如何选择为begin()调用哪个重载?

情况 1 不明确,因为 return 类型不参与重载决议, case 2 等同于 case 3 因为 const 在 return 类型中被丢弃 案例3:

const Test t1;
t1.begin() // calls int begin() const;
Test t2;
t2.begin() // calls int begin();

来自cppreference.com

A non-static member function can be declared with a const, volatile, or const volatile qualifier (this qualifier appears after the name of the function in function declaration). Differently cv-qualified functions have different types and so may overload each other. In the body of a cv-qualified function, the this pointer is cv-qualified, e.g. in a const member function, only other const member functions may be called normally. (A non-const member function may still be called if const_cast is applied or through an access path that does not involve this.)

成员函数有一个隐式参数,它是 class 本身的实例。所以你可以认为你的函数看起来像:

// 1) compile-error as const-qualifications on return doesn't distinguish
//    the functions - you cannot overload on return type
int begin(Test& );
const int begin(Test& );

// 2)
int begin(Test& );
const int begin(const Test& );

// 3)
int begin(Test& );
int begin(const Test& );

对于第二种和第三种情况,函数上的 const 限定等同于隐式参数是对常量的引用。所以当你有类似的东西时:

Test{}.begin();

调用 begin() 使用对非常量 Test 的引用作为隐式第一个参数。 begin() 的两个重载都是可行的,都不需要转换,因此首选最少 cv 限定的引用,即非 const 限定的函数。

相反,当您拥有:

(const Test{}).begin();

我们正在调用 begin() 并引用 const Test。所以非 const 限定的函数不是一个可行的候选者(你不能将 const-ref 传递给期望非 const-ref 的函数),所以最好的可行候选者是唯一可行的候选者:int begin() const

要记住的几条规则:

  1. 不能仅基于 return 类型重载方法。这会导致您的案例 1 中出现错误。

  2. 当按值 returning 时,const 限定符是多余的。在你的情况 2 中,编译器警告你这一点。

  3. class 的每个非静态方法都有一个隐式参数。在方法调用时,this 被分配给调用该方法的实例。方法声明末尾(方法体之前)的 const 关键字适用于此隐式参数。您实质上是在说函数体不会修改实例的状态(数据成员)。如果在 const 实例上调用该方法,则需要定义 const 方法。此外,您可以仅根据是否为 ​​const 的事实来重载该方法。