在C ++中,如果我定义一个复制构造函数和operator =对该类采用非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);
};
答案 0 :(得分:7)
不,如果您定义了复制构造函数和赋值运算符,编译器将不会隐式声明或定义它自己的。请注意, copy-constructor 的定义允许参数由const或非const引用获取,因此构造函数确实是 copy-constructor 。同样适用于operator=
[省略了大部分细节,特别是在什么情况下隐式声明的特殊成员函数也将隐式定义]
12.8 [class.copy] / 2如果第一个参数的类型为X&,const X&,volatile X& X,则X类的非模板构造函数是一个复制构造函数。或const volatile X&,并且没有其他参数,或者所有其他参数都有默认参数(8.3.6)。
12.8 [class.copy] / 7如果类定义没有显式声明复制构造函数,则会隐式声明一个。
12.8 [class.copy] / 17用户声明的复制赋值运算符X :: operator =是类X的非静态非模板成员函数,其中只有一个类型为X,X&,const X&的参数。 ,易变的X&或const volatile X&。
12.8 [class.copy] / 18如果类定义没有显式声明一个复制赋值运算符,则会隐式声明一个。
答案 1 :(得分:1)
不,一旦声明了自己的复制构造函数或复制赋值运算符(无论它是否使用规范const
),编译器将不再为您执行此操作。
但是通过非const引用来做这件事几乎是违反最小惊喜原则的教科书范例。每个人都希望可以从中分配const对象,并且右侧不会发生变异。第一个并不是很糟糕,因为编译器会捕获它,但第二个可能导致各种难以发现的错误。
如果你正在尝试实现移动语义而你不能使用C ++ 11,我会建议创建一个特殊的移动方法,而根本不允许“移动”构造。如果你可以使用C ++ 11,那么使用内置右值引用。