菜鸟在这里。以下是我在书籍示例中遇到的类定义的片段:
double& operator[](int i);
double operator[](int i) const;
我的问题是:为什么这不是模棱两可的?编译项目文件时,编译器不会给出任何错误。此外,在下面(valarray<double>
例如,想象 AnyClass 包含一个对象,我想直接访问它):
AnyClass test;
cout << test[2]
编译器使用哪个版本?
菜鸟在这里。以下是我在书籍示例中遇到的类定义的片段:
double& operator[](int i);
double operator[](int i) const;
我的问题是:为什么这不是模棱两可的?编译项目文件时,编译器不会给出任何错误。此外,在下面(valarray<double>
例如,想象 AnyClass 包含一个对象,我想直接访问它):
AnyClass test;
cout << test[2]
编译器使用哪个版本?
它不是模棱两可的,因为它const
是签名的一部分,可用于重载解决方案。因此,如果您operator[]
在非常量对象上使用,它会选择重载,const
因为这是最具体的。如果你在 const 对象上使用它,它会选择重载,const
因为这是唯一适用的。
如果在const
对象上调用,const
将使用该版本,否则使用另一个。
这就是编译器解决歧义的方式。
AnyClass test;
const AnyClass const_test;
std::cout << test[2]; // calls operator[](int)
std::cout << const_test[2]; // calls operator[](int) const
要理解这一点,您通常只需要意识到const
参数上的 a 足以消除调用的歧义:
#include <iostream>
void foo(char* ptr)
{
std::cout << "mutable: " << ptr << std::endl;
}
void foo(const char* ptr)
{
std::cout << "const: " << ptr << std::endl;
}
int main()
{
const char* constHello = "hello";
char mutableHello[] = "hello";
foo(constHello);
foo(mutableHello);
}
这打印:
常量:你好
可变:你好
编译器将尽可能选择限制最少的重载。因此,如果您在过载char*
时使用 a char*
,它将选择它;但如果没有,编译器将决定将其强制转换为 aconst char*
是可行的转换(显然,反之亦然)。
现在,非常简单的事情是所有方法都传递一个this
指针作为任何函数的第一个参数。为简单起见,隐藏此参数。const
方法末尾的 限定参数this
。因为,正如我们刚刚看到的,const
指针上的 a 足以消除重载的歧义,这将有效地工作。