我对overloading和const声明规则感到很困惑。 这有两件事让我感到困惑,也许你可以帮助我找到更深层次的误解,导致他们对我感到困惑。 ;)
第一期:
我的编译器允许这样:
void f(int & x) {
std::cout << "plain f" << std::endl;
}
void f(const int & x) {
std::cout << "const f" << std::endl;
}
但是以下会导致编译错误(函数已经有一个正文):
void f(int x) {
std::cout << "plain f" << std::endl;
}
void f(const int x) {
std::cout << "const f" << std::endl;
}
我认为这是有道理的,因为我认为const只是告诉编译器传递的对象没有改变,在第二种情况下它仍然被复制。但如果这是正确的,为什么我可以使用const?
重载函数换句话说,为什么我使用编译版本并调用这样的函数:
int x1 = 5;
const int x2 = 5;
f(x1);
f(x2);
我得到“普通f”和“const f”而不是“const f”两次吗?显然现在我也使用const来告诉编译器调用哪个函数不仅引用不会改变。这变得更加混乱,因为如果我删除“普通”版本它工作得很好并且两次调用“const”版本。
现在我的实际问题是什么?我想知道这种行为背后的想法是什么,因为否则记住它是非常困难的。
答案 0 :(得分:4)
n3337 13.1
[注意:如8.3.5中所述,函数声明具有 等效参数声明声明相同的函数和 因此不能超载:仅在存在或不存在时才发生
- di3的参数声明 const和/或volatile的等价物。也就是说,const和 当时,将忽略每个参数类型的volatile类型说明符 确定正在声明,定义或调用哪个函数。 [ 示例:
typedef const int cInt; int f(int); int f(const int); // redeclaration of f(int) int f(int) { /* ... */ } // definition of f(int) int f(cInt) { /* ... */ } // error: redefinition of f(int)
- 结束 例子]只有最外面的const和volatile类型说明符 此参数类型规范的级别将被忽略 时尚; const和volatile类型说明符隐藏在参数中 类型规范是重要的,可用于区分 重载函数声明.124特别是对于任何类型的T, “指向T的指针”,“指向const T的指针”和“指向易失性T的指针” 被认为是不同的参数类型,如“对T的引用” “引用const T”和“引用volatile T”。
答案 1 :(得分:1)
我认为const只是告诉编译器对象是什么 传递不会改变,在第二种情况下,它仍然被复制
你是对的。因为在第二种情况下它仍然被复制,因此const
对调用者没有任何影响,标准定义void f(const int x)
和void f(int x)
具有相同的签名。因此它们发生碰撞,你试图两次定义相同的函数。
因为在第一种情况下,尚未被复制,void f(const int &x)
和void f(int &x)
具有不同的签名。因此他们超载。
在你的第一种情况下,禁止以int&
为f
作为参数调用x2
版本,因为这将创建一个对const对象的非const引用而没有任何显式看得见。这样做会破坏const系统的目的(如果你想破坏const-safety,你必须明确地使用强制转换)。因此,使用参考参数进行函数的常量和非常量重载是有意义的。
在第二种情况下,副本源的常量与目标的常量之间没有关系。您可以从非常量变量初始化const变量,或从常量变量初始化const变量。这不会导致任何问题,也不会破坏const安全性。这就是为什么标准通过定义f
的两个“不同”版本实际上是相同的功能来帮助明确这一点。