如果 C++ class 同时包含 const 引用和非 const 引用复制构造函数怎么办?
what if C++ class contains both const reference and non-const reference copy constructor?
片段 1:
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
};
int main(){
C c1;
C c2 = c1;
return 0;
}
输出:const拷贝构造函数调用
片段 2:
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
C(C& c){
cout<<"non-const copy constructor called.\t "<<endl;
}
};
int main(){
C c1;
C c2 = c1;
return 0;
}
输出:调用了非常量复制构造函数
片段 3:
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
C(C c){
cout<<"non-const copy constructor called.\t "<<endl;
}
};
int main(){
C c1;
C c2 = c1;
return 0;
}
输出:错误:复制构造函数必须通过引用传递它的第一个参数
我很困惑:
- 对于片段 2,为什么这里的非 const 复制构造函数有效?为什么调用非 const 复制构造函数,而不是 const 复制构造函数。
- 对于片段 3,我知道复制构造函数必须使用 const 引用来避免无限递归。但是这里class C已经得到了
C(const C& c)
,C(C c)
不会造成无限递归,为什么还是不行?
片段 1:一个带有 const T&
的标准复制构造函数。快乐的世界。
片段 2:
您有效地完成了复制构造函数的重载 - 一个采用引用 T&
,另一个采用常量引用 const T&
。
请注意:class T 的任何构造函数具有一个 T &
或 const T &
类型的强制参数(它也可能有更多的默认参数)是一个复制构造函数.
因此,对于编译器而言,这一切都归结为找到 最适合 的重载解析,其完成方式如下:
Standard conversion sequence S1 is a better conversion sequence than
standard conversion sequence S2 if:
- ....
- S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers,
and the type to which the reference initialized by S2 refers is more
cv-qualified than the type to which the reference initialized by S1
refers.
所以写
C c1;
C c2 = c1;
将调用非常量复制构造函数,因为它更匹配,但是,
写作,
const C c1;
C c2 = c1;
将调用 const 复制构造函数(您可以检查),因为现在带有 const 的复制构造函数是唯一可行的匹配项。
片段 3 对于编译器来说完全是错误的。
C(C c){
cout<<"non-const copy constructor called.\t "<<endl;
}
您不能拥有带有签名的方法 C(C c)
。编译器认为您正在尝试编写复制构造函数而错过了 &
的编写,因此报告了错误。删除它,它工作正常。
@除非你有很好的理由,否则 永远不要使用 C(C& c)
作为你的复制构造函数。不要跳过 const
,因为改变您从中制作副本的对象没有多大意义。
for snippet 2, why the non-const copy constructor here is valid? why non-const copy constructor was called, rather than the const one.
考虑您针对此问题的代码,但在下面进行更改并添加注释 // (*)
:
int main(){
const C c1; // (*) <- See change here
C c2 = c1;
return 0;
}
这调用了const
copy ctor 版本。它真的与碰巧是构造函数的函数无关——如果一个函数有两个重载,一个接受引用,一个接受 const
引用,那么非常量对象将被第一个调用,并且const
个对象。
for snippet 3, I know that copy constructor must use const reference to avoid infinite recursion. But Here class C has got C(const C& c), C(C c) won't cause infinite recursion, why it still doesn't work?
考虑以下代码,并注意没有调用正在进行(main
的内容几乎被删除)。
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
C(C c){
cout<<"non-const copy constructor called.\t "<<endl;
}
};
int main(){
// Note that nothing is creating C instances at all.
return 0;
}
这会导致完全相同的错误 - 编译器只是拒绝使用此接口编译 class,无论是否有东西试图调用它。
引用 this question 的回答“它被 §12.8/3 中的标准禁止:
A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv- qualified) X and either there are no other parameters or else all other parameters have default arguments.
"
片段 1:
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
};
int main(){
C c1;
C c2 = c1;
return 0;
}
输出:const拷贝构造函数调用
片段 2:
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
C(C& c){
cout<<"non-const copy constructor called.\t "<<endl;
}
};
int main(){
C c1;
C c2 = c1;
return 0;
}
输出:调用了非常量复制构造函数
片段 3:
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
C(C c){
cout<<"non-const copy constructor called.\t "<<endl;
}
};
int main(){
C c1;
C c2 = c1;
return 0;
}
输出:错误:复制构造函数必须通过引用传递它的第一个参数
我很困惑:
- 对于片段 2,为什么这里的非 const 复制构造函数有效?为什么调用非 const 复制构造函数,而不是 const 复制构造函数。
- 对于片段 3,我知道复制构造函数必须使用 const 引用来避免无限递归。但是这里class C已经得到了
C(const C& c)
,C(C c)
不会造成无限递归,为什么还是不行?
片段 1:一个带有 const T&
的标准复制构造函数。快乐的世界。
片段 2:
您有效地完成了复制构造函数的重载 - 一个采用引用 T&
,另一个采用常量引用 const T&
。
请注意:class T 的任何构造函数具有一个 T &
或 const T &
类型的强制参数(它也可能有更多的默认参数)是一个复制构造函数.
因此,对于编译器而言,这一切都归结为找到 最适合 的重载解析,其完成方式如下:
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if:
- ....
- S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.
所以写
C c1;
C c2 = c1;
将调用非常量复制构造函数,因为它更匹配,但是,
写作,
const C c1;
C c2 = c1;
将调用 const 复制构造函数(您可以检查),因为现在带有 const 的复制构造函数是唯一可行的匹配项。
片段 3 对于编译器来说完全是错误的。
C(C c){
cout<<"non-const copy constructor called.\t "<<endl;
}
您不能拥有带有签名的方法 C(C c)
。编译器认为您正在尝试编写复制构造函数而错过了 &
的编写,因此报告了错误。删除它,它工作正常。
@除非你有很好的理由,否则 永远不要使用 C(C& c)
作为你的复制构造函数。不要跳过 const
,因为改变您从中制作副本的对象没有多大意义。
for snippet 2, why the non-const copy constructor here is valid? why non-const copy constructor was called, rather than the const one.
考虑您针对此问题的代码,但在下面进行更改并添加注释 // (*)
:
int main(){
const C c1; // (*) <- See change here
C c2 = c1;
return 0;
}
这调用了const
copy ctor 版本。它真的与碰巧是构造函数的函数无关——如果一个函数有两个重载,一个接受引用,一个接受 const
引用,那么非常量对象将被第一个调用,并且const
个对象。
for snippet 3, I know that copy constructor must use const reference to avoid infinite recursion. But Here class C has got C(const C& c), C(C c) won't cause infinite recursion, why it still doesn't work?
考虑以下代码,并注意没有调用正在进行(main
的内容几乎被删除)。
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
C(C c){
cout<<"non-const copy constructor called.\t "<<endl;
}
};
int main(){
// Note that nothing is creating C instances at all.
return 0;
}
这会导致完全相同的错误 - 编译器只是拒绝使用此接口编译 class,无论是否有东西试图调用它。
引用 this question 的回答“它被 §12.8/3 中的标准禁止:
A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv- qualified) X and either there are no other parameters or else all other parameters have default arguments.
"