9

可能重复:
C++ 中 const 声明之间的区别

#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,冲突l6l7但只有冲突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. l12请详细说明and之间的冲突l13,即使l12不包含const关键字
  4. 如果是琐碎的问题,真的很抱歉
4

6 回答 6

6

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

首先,Bar constconst Bar已经是相同的意思,所以他们会自动有问题。但是作为函数参数,const它不适用于重载,因此Bar函数的版本也看起来相同。参数中的const仅告诉编译器您不打算在函数体中修改它。

出于同样的原因,Bar*并且Bar* const被视为相同:const适用于参数的值(不是指向的值)并且不参与重载,因此您定义了相同的函数。

另一方面const Bar*意味着完全不同的东西:指向const对象(类型Bar)的非常量指针。由于类型不同,它确实参与了重载并允许该函数是唯一的。

于 2013-01-09T18:04:37.490 回答
2

将 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

于 2013-01-09T17:54:21.127 回答
1

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

但是,当您谈论指针时,如果您将指向常量的指针与指向非常量的指针传递给调用者,则调用者会有所不同(一个不会更改您的东西,另一个可能会)。这就是 l11 和 l12 不冲突的原因。

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

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

于 2013-01-09T17:58:19.440 回答
0

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

但是,在以参数为指针的情况下,当您调用foo(BarPointer);ifBarPointer被声明为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.
于 2013-01-09T17:57:26.500 回答
0
void foo(const Bar x){}
void foo(Bar const x){}

上述两个是相同的,因为两者都 sayxBartype 并且 it is 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对象都是非. 因此,ness of是函数的实现细节。xconstconstx

void foo(const Bar* x){}

在这里,您表示x指向的Bar对象是const. 这与前两种情况不同,因此不存在冲突。

于 2013-01-09T18:03:04.563 回答
0

对于前三个函数 -如果变量按const传输,重载分辨率无关紧要。在堆栈上创建的参数副本,如果这个副本从外部(调用者)的角度改变或没有改变,它是没有意义的。它对功能本身(内部)很重要。

对于第二种情况,基于指针的函数,它是函数重载解析的重要部分,因为副本不是在堆栈上创建的,从外部(调用者)的角度来看,这意味着函数将或不修改参数的值。

对于最后两个函数,对编译器使用 say:有指向 的x指针Bar,并且 I 指向的这个Barx可能会改变。但是在第一种情况下,您可以更改与第二种情况相反的指针x本身的值(例如,指向另一个)。Bar在这里,我们处于第一种情况 - 指针本身的副本在堆栈上,如果它们在函数内部发生变化,重载决议没有意义。

于 2013-01-09T18:16:39.930 回答