C++重载getter两次,一次返回指针,另一次返回常量引用,都失败了

C++ overloading getter twice, one returning pointer and the other const reference, fails

本文关键字:一次 返回 引用 失败 常量 指针 两次 C++ getter 重载      更新时间:2023-10-16

正如标题所说,我试图重载getter,以向成员变量返回指针(mutator方法)和常量引用(inspector方法)。

请注意,上面链接中的示例使用了引用和常量引用,我不希望这样。

#include <vector>
class A {
public:
    A() : v() {}
    const std::vector<int>& get_v() const {return  v;}
    std::vector<int>*       get_v()       {return  &v;}
private:
    std::vector<int> v;
};
int main() {
    A a;
    a.get_v()->size();  // ok
    a.get_v().size();   // error: request for member ‘size’ in ‘a.A::get_v()’,
                        //        which is of pointer type ‘std::vector<int>*’
                        //        (maybe you meant to use ‘->’ ?)
}

在我尝试使用它抛出上面给出的错误描述之前,它似乎还可以工作。这种不当行为有原因(和解决办法)吗?

在我尝试使用它抛出上面给出的错误描述之前,它似乎还可以工作。

a.get_v().size();

该代码显然是错误的,因为std::vector<int>* get_v()返回了一个指针。关于试图访问指针的成员,错误消息非常清楚,这是你不能做的。要修复它,你需要使用箭头运算符来取消引用指针,就像在上面一行所做的那样。

你怎么能说出用了哪一个?

一个重载是非常数,并且只能在非常数对象上调用。另一个是const,可以对const和非常量对象调用,但永远不会对非常量对象进行调用,因为非常量重载是首选。它是首选,因为它不需要将非常量对象参数转换为常量。对const成员函数的调用将需要这样的转换。与那些需要转换的重载相比,不需要转换参数的重载更受欢迎。因此,总是为非常量对象参数调用非常量版本。

下面的也失败了

std::vector<int>& v = a.get_v();

a仍然是非常数,因此选择了返回指针的重载。不能将非指针引用绑定到指针。


如果你想调用在非常量对象上返回常量引用的函数,那么你必须给它另一个名称,这样它就不会有首选的重载。


你有这方面的参考资料吗?

我将引用cppreference.com,因为这是非常基本的东西——尽管规则有点复杂。如果你怀疑这个标准的正确性,就查一下。

首先,关于成员函数重载的一些信息:

如果任何候选函数是成员函数(静态或非静态),但不是构造函数,则将其视为具有一个额外的参数(隐式对象参数),该参数表示调用它们的对象,并出现在第一个实际参数之前。

我认为很明显,两个重载都是候选者,因为它们有相同的名称。它们也是可行的,因为它们有正确数量的论据,并且是可转换的。那么,哪种过载是首选?

对于每对可行函数F1和F2,对从第i个参数到第i个自变量的隐式转换序列进行排序,以确定哪一个是更好的

如果F1的所有变元的隐式转换不比F2的所有变位的隐式转化差,则F1被确定为比F2更好的函数,并且

1) 至少有一个F1自变量的隐式转换比F2 自变量的相应隐式转换好

好的,所以更好的转换序列是优选的。。。哪个更好?让我们先弄清楚转换序列是什么。唯一的参数是隐式对象参数。传递的参数的类型为非常量A

作为非常数的重载有一个类型为非常数A的隐式对象参数(它在这里并不真正相关,但在实践中它是作为指针传递的)。非常量A不需要转换为非常量A,因为它是完全匹配的。这将被视为身份转换。

常量重载具有类型为const A的隐式对象参数。可以将CCD_ 8隐式地转换为CCD_。

这两个转换级别相同。在这种情况下,需要通过一长串规则。这些都不适用,直到最后一部分:

f) 或者,如果不是这样,S1和S2仅在资格转换上不同,并且S1的结果的cv资格是S2 的结果的cv资格的子集

标识转换是常量转换的一个子集。所以更好。我认为身份可能也更好,因为在计算身份转换时,cv转换需要两次转换。。。不过,我找不到关于这方面的规则。

A a不是常量,因此编译器无法应用const std::vector<int>& get_v() const {return v;}

这项工作:

#include <vector>
class A {
public:
    A() : v() {}
    const std::vector<int>& get_v() const {return  v;}
    std::vector<int>*       get_v()       {return  &v;}
private:
    std::vector<int> v;
};
int main() {
    A a;
    a.get_v()->size();  // ok
    const A b;
    b.get_v().size();   // ok
}

编辑-添加解释

b.get_v()->size();为什么失败?

从那里:

最佳可行功能

对于每对可行函数F1和F2,对从第i个参数到第i个自变量的隐式转换序列进行排序,以确定哪一个更好[…]

1) 至少有一个F1自变量的隐式转换比F2 自变量的相应隐式转换好

案例1:const std::vector<int>& get_v() const {return v;}我们不需要转换任何

案例2:std::vector<int>* get_v() {return &v;}我们需要将指针thisconst A转换为A——我们不能隐式执行,只能使用const_cast

所以编译器选择了情况1。