#include <iostream>
class Bar{};
void foo(const Bar x){} //l5
void foo(Bar x){} //l6
void foo(Bar const x){} //l7
////pointer functions
void foo(const Bar* x){} //l11
void foo(Bar* x){} //l12
void foo(Bar* const x){} //l13
编译器输出:(长话短l5
,l6
,l7
冲突;但只有l12
,l13
冲突)
untitled.cpp:6:6: error: redefinition of ‘void foo(Bar)’
untitled.cpp:5:6: error: ‘void foo(Bar)’ previously defined here
untitled.cpp:7:6: error: redefinition of ‘void foo(Bar)’
untitled.cpp:5:6: error: ‘void foo(Bar)’ previously defined here
untitled.cpp:13:6: error: redefinition of ‘void foo(Bar*)’
untitled.cpp:12:6: error: ‘void foo(Bar*)’ previously defined here
发生了什么?
l12
和l13
之间,即使l12
不包含const
关键字答案 0 :(得分:5)
“问题”是参数值的const
不参与重载!
首先,Bar const
和const Bar
已经是相同的含义,因此它们会自动出现问题。但作为函数参数,const
不适用于重载,因此函数的Bar
版本也看起来也一样。 paremeter中的const
只告诉编译器你不打算在函数体中修改它。
出于同样的原因,Bar*
和Bar* const
的处理方式相同:const
适用于参数的值(不是指向的值)并且不参与重载,所以你已经定义了相同的功能。
另一方面,const Bar*
意味着完全不同的东西:指向const
对象(类型为Bar
)的非常量指针。由于类型不同,它确实参与重载并允许该函数是唯一的。
答案 1 :(得分:1)
是否在类型名称之前或之后放置const无关紧要。
15和17具有相同的参数参数列表 这两个函数被认为具有相同的原型并且是重复的。
功能#1
void foo(const int x) {
return;
}
功能#2 - 重复的参数参数列表
void foo( int const x) {
return;
}
const的位置与你所拥有的例子中的15和17相同。
要么根据维基百科工作:
答案 2 :(得分:1)
基本上,因为C ++在调用函数时复制值,所以没有什么可以区分前三个和调用者的角度。 (调用者知道函数不能改变它自己传入的值,所以每个函数参数在很多方面都是隐式不变的,从调用者的角度来看,无论如何)。
当你谈论指针时,如果你传递指向常量的指针vs指向非常量的指针,那么调用者就会有所不同(一个不会改变你的东西,另一个可能会改变)。这就是l11和l12不冲突的原因。
l12和l13冲突但因为它们都是指向Bar *的指针(一个是const指针,一个不是,所以问题与l5-l7相同,与调用者没有区别)。
最后一点可能有点棘手 - 请注意,虽然int const *a
与const int *a
相同,但这些 与int * const a
不同,前两个是指向常量int的指针,另一个是指向int的常量指针(即指针的值在以后不能改变)。
答案 3 :(得分:0)
前三个产生冲突的原因是编译器无法确定在任何情况下使用哪个函数。当你调用foo(BarObject);
时,无论是否将BarObject
声明为const
,编译器都可以很好地使用它们。
但是在那些带有参数作为指针的情况下,如果foo(BarPointer);
如果BarPointer
被声明为const Bar* BarPointer;
则调用]11
,编译器将选择const
,因为它确保了对象指向将不会在函数中修改(不是像前三个一样通过值时的情况)。如果不是]12
,则不知道是否应该拨打]13
或Bar* const x
,因为x
的含义是,“const Bar x // x is an immutable copy of the original parameter.
Bar const x // same as above and gets compiled, but cdecl says it is a syntax error.
const Bar* x // x points to an object that can't be changed.
Bar* const x // x can't point to any other object than the parameter passed.
不能指向除了作为参数传递的内容以外的任何内容“这与调用者无关。
对声明的小参考:
{{1}}
答案 4 :(得分:0)
void foo(const Bar x){}
void foo(Bar const x){}
以上两者完全相同,因为两者都说x
属于Bar
类型且为const
。
void foo(Bar x){}
这个与上面的2冲突,因为x
是否const
是你的函数的实现细节,并且被编译器从函数签名中丢弃。因此,所有3个函数最终都具有相同的签名void foo( Bar x )
。
void foo(Bar* x){}
void foo(Bar* const x){}
这与之前的案例类似;您指示指针x
为const
,即您不会将x
重新指向函数中的其他内容。在这两种情况下,Bar
指向的x
对象都是非const
。因此const
的{{1}}是该函数的实现细节。
x
此处您指出void foo(const Bar* x){}
指向x
对象,Bar
。这与前两种情况不同,因此没有冲突。
答案 5 :(得分:0)
对于前三个函数 - const
在由值传输的大小写变量中对重载分辨率不重要。在堆栈上创建的参数的副本,如果从外部(调用者)的角度来看该副本是否发生了变化,则没有意义。功能本身(内部)很重要。
对于第二种情况,基于指针的函数,它是函数重载解析的重要部分,因为副本不是在堆栈上创建的,而且从外部(调用者)的角度来看,它意味着函数是否会修改参数&# 39; s值。
对于最后两个函数,请对编译器使用:指向x
的{{1}}指针,Bar
指向的Bar
值可能会更改。但在第一种情况下,您可以更改指针x
本身的值(例如,指向另一个x
)与第二种情况相反。在这里我们处于第一种情况 - 指针的副本本身就在堆栈中,如果它们在函数内部发生了变化,它对于重载分辨率没有意义。