通过拷贝相同类的另一个对象的状态来初始化一个对象。
使用:当通过数值传递,通过数值返回,或明确拷贝一个对象
赋值运算符
返回什么:一般通过引用返回*this,就是说用户自己定义的类的赋值遵守和内部类型相同的约定,赋值也可用作表达式,也即能够级联
自我赋值语法上没有任何错误,但如果你没有很好的实现赋值运算符,那么灾难可能就在等着你。
所以你必须确保自我赋值无害,也就是要加入自我赋值的检测
[cpp]
CAssignment& CAssignment::operator=(const CAssignment& a)
{
if( this == &a )
return *this;
//….赋值该作的工作
}
保证赋值运算符只有两种结果:完全成功、原封不动留下对象并抛出异常
[cpp]
CAssignment& CAssignment::operator=(const CAssignment& a)
{
if( this == &a )
return *this;
CTemp* t = new CTemp;
//…..
delete _tmp;
_tmp = t;
return *this;
}
派生类使用赋值运算符
派生类中的赋值运算符首先调用其直接基类赋值运算符(对声明在基类里的成员对象赋值),然后再调用它的成员对象的赋值运算符(改变在派生类里声明的那些成员对象)。这些赋值通常应该与基类和成员对象在该类的定义里出现的次序相同。
[cpp]
CDerived& CDerived::operator=(const CDerived& r)
{
CBase::operator=(r);
_c = r._c;
return *this;
}
重载赋值运算符的正确形式:
c++的设计者stroustrup下了很大的功夫想使用户自定义类型尽可能地和内部类型的工作方式相似。为此他做了很多努力(如重载运算符,写类型转换函数和拷贝构造函数,等等)。而你也该继续做下去。
让我们看看赋值。用内部类型的情况下,赋值操作可以象下面这样链起来:
int w, x, y, z; w = x = y = z = 0;
所以,你也应该可以将用户自定义类型的赋值操作链起来:
CString w, x, y, z; // MFC “自定义”的类型
w = x = y = z = "hello";
因为赋值运算符的结合性天生就是由右向左,所以上面的赋值可以解析为:
w = (x = (y = (z = "hello"))); <=>
w.operator=(x.operator=(y.operator=(z.operator=("hello"))));
这个格式说明了w.operator=, x.operator=和y.operator=的参数是前一个operator=调用的返回值。所以operator=的返回值必须可以作为一个输入参数被函数自己接受。一般情况下operator=输入应该是类对象或类对象的引用,从效率来说后者好过前者 ,所以输入和返回的都应是类对象的引用。
又因为有
int x, y,z; (x = y) = z ;
所以如下语句也应正确
CString x, y, z; ( x = y) = z;
那么operator=的返回不能是const(因为常量不能赋左值)
又有
CString x; x = “Hello”; <=>
const CString temp(“Hello”); //产生临时对象,为什么是const
x = temp;
所以为保证上面的语句成立, operator=的输入应是const
所以最好的实现是 T& operator=(const T&);