如果使用非常量参数定义构造函数和运算符,是否仍会得到默认的复制构造函数和运算符? 在C++中,如果我定义了一个拷贝构造函数和运算符=对类使用非const引用,编译器是否仍然为const引用提供默认版本? struct Test { Test(Test &rhs); Test &operator=(Test &rhs); private: // Do I still need to declare these to avoid automatic definitions? Test(const Test &rhs); Test &operator=(const Test &rhs); };

如果使用非常量参数定义构造函数和运算符,是否仍会得到默认的复制构造函数和运算符? 在C++中,如果我定义了一个拷贝构造函数和运算符=对类使用非const引用,编译器是否仍然为const引用提供默认版本? struct Test { Test(Test &rhs); Test &operator=(Test &rhs); private: // Do I still need to declare these to avoid automatic definitions? Test(const Test &rhs); Test &operator=(const Test &rhs); };,c++,constants,language-lawyer,default-copy-constructor,C++,Constants,Language Lawyer,Default Copy Constructor,不,如果定义了复制构造函数和赋值运算符,编译器将不会隐式声明或定义它自己的。请注意,复制构造函数的定义允许常量或非常量引用获取参数,因此您的构造函数实际上是一个复制构造函数。对于运算符= [省略大部分细节,特别是在什么情况下隐式声明的特殊成员函数也将被隐式定义] 12.8[class.copy]/2类X的非模板构造函数是复制构造函数,如果其第一个参数的类型为X&、常量X&、volatile X&或常量volatile X&,并且没有其他参数,或者所有其他参数都有默认参数(8.3.6) 12.8[

不,如果定义了复制构造函数和赋值运算符,编译器将不会隐式声明或定义它自己的。请注意,复制构造函数的定义允许常量或非常量引用获取参数,因此您的构造函数实际上是一个复制构造函数。对于
运算符=

[省略大部分细节,特别是在什么情况下隐式声明的特殊成员函数也将被隐式定义]

12.8[class.copy]/2类X的非模板构造函数是复制构造函数,如果其第一个参数的类型为X&、常量X&、volatile X&或常量volatile X&,并且没有其他参数,或者所有其他参数都有默认参数(8.3.6)

12.8[class.copy]/7如果类定义没有显式声明副本构造函数,则隐式声明副本构造函数

12.8[class.copy]/17用户声明的复制赋值运算符X::operator=是类X的非静态非模板成员函数,只有一个类型为X、X&、const X&、volatile X&或const volatile X&

12.8[class.copy]/18如果类定义没有显式声明复制赋值运算符,则隐式声明一个


不,一旦您声明了自己的复制构造函数或复制赋值运算符(无论它是否使用规范的
const
ness),编译器将不再为您执行此操作

但是,通过非常量引用来实现这一点几乎是违反最小意外原则的教科书上的例子。每个人都希望const对象可以从中分配,并且右侧不会发生变异。第一个并不像编译器捕捉到的那么糟糕,但第二个可能会导致各种难以发现的bug

如果您试图实现移动语义,但无法使用C++11,我建议您创建一个特殊的移动方法,并且完全不允许“移动”构造。如果可以使用C++11,则使用内置的右值引用