函数声明中的const关键字位置

时间:2013-01-09 17:46:45

标签: c++ pointers const

  

可能重复:
  Difference between const declarations in C++

#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

编译器输出:(长话短l5l6l7冲突;但只有l12l13冲突)

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

发生了什么?

  1. 每个声明的含义是什么
  2. 为什么所有3个声明都与对象函数冲突,而只有2个与指针函数冲突?
  3. 请详细说明冲突在l12l13之间,即使l12不包含const关键字
  4. 如果有琐碎的问题,真的很抱歉

6 个答案:

答案 0 :(得分:5)

“问题”是参数值的const不参与重载!

首先,Bar constconst 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相同。

要么根据维基百科工作:

http://en.wikipedia.org/wiki/Const-correctness

答案 2 :(得分:1)

基本上,因为C ++在调用函数时复制值,所以没有什么可以区分前三个和调用者的角度。 (调用者知道函数不能改变它自己传入的值,所以每个函数参数在很多方面都是隐式不变的,从调用者的角度来看,无论如何)。

当你谈论指针时,如果你传递指向常量的指针vs指向非常量的指针,那么调用者就会有所不同(一个不会改变你的东西,另一个可能会改变)。这就是l11和l12不冲突的原因。

l12和l13冲突但因为它们都是指向Bar *的指针(一个是const指针,一个不是,所以问题与l5-l7相同,与调用者没有区别)。

最后一点可能有点棘手 - 请注意,虽然int const *aconst int *a相同,但这些 int * const a不同,前两个是指向常量int的指针,另一个是指向int的常量指针(即指针的值在以后不能改变)。

答案 3 :(得分:0)

前三个产生冲突的原因是编译器无法确定在任何情况下使用哪个函数。当你调用foo(BarObject);时,无论是否将BarObject声明为const,编译器都可以很好地使用它们。

但是在那些带有参数作为指针的情况下,如果foo(BarPointer);如果BarPointer被声明为const Bar* BarPointer;则调用]11,编译器将选择const,因为它确保了对象指向将不会在函数中修改(不是像前三个一样通过值时的情况)。如果不是]12,则不知道是否应该拨打]13Bar* 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){}

这与之前的案例类似;您指示指针xconst,即您不会将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)与第二种情况相反。在这里我们处于第一种情况 - 指针的副本本身就在堆栈中,如果它们在函数内部发生了变化,它对于重载分辨率没有意义。