一、中心思想
1、令赋值操作符返回一个*this的引用;
2、确保“自我赋值”时,operator=有良好行为(特别是异常安全)。。包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap;
3、拷贝函数(拷贝构造函数和拷贝操作符)应该确保复制“对象内的所有成员变量”以及“所有基类成分”;
4、不要师徒用某个拷贝函数实现另外一个拷贝函数。。。。应该将共同机能的代码放进第三个函数,并由两个拷贝函数共同调用
二、内容简介
1、如何处理自我赋值,特别是行为像指针的类
(1)几种潜在的自我赋值
1)a[i] = a[j];//i=j的时候,就是自我赋值
2)*px = *py;//当两个指针指向同一个内容时
3)两个对象来自同一个继承体系,不需要声明为相同类型就可能造成别名。
e.g
class Base{......};
class Derived: publilc Base {......};
void dosomething(const Base& rb, Derived* pd);//rb和*pd有可能是同一个对象
(2)几种“自我赋值”的处理方式
e.g
考虑如下的类
class Bitmap {...};
class Widget{...
......
private:
Bitmap* pb;
};
1)不安全的实现版本
Widget& Widget::operator=(const Widget& rhs)
{
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
note:
1、赋值符号右边的对象保持不变;
2、若rhs与*this是同一个对象,那么执行后的this指针可能会指向一个没有内容的对象,即已经被删除的对象。
2)加上证同测试的不安全版本(异常安全问题)
Widget& Widget::operator=(const Widget& rhs)
{
if(this == &rhs) return *this; //证同测试
delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
note:
此代码可以避免1)中2的问题。。。
但是,若new Bitmap 出现了问题(分配时内存不足或因为Bitmap的拷贝构造函数抛出异常),不同对象进行赋值时,就会出现问题,导致最终this指针会指向一个被删除的对象。
3)安全版本
Widget& Widget::operator=(const Widget& rhs)
{
Bitmap* cpb = pb; //记住原先的pb;
pb = new Bitmep(*rhs.pb);
delete cpb;
return *this;
}
note:
即使此时new Bitmap 发生异常抛出,原来的pb仍然可以保持原样。。。
3)两种使用swap()函数的较佳版本
class Widget{
......
void swap(Widget& rhs); //定义自己的swap函数;
......
};
Widget& Widget::operator=(const Widget& rhs)
{
Widget temp(rhs);
swap(temp);
return *this;
}
或者:
Widget& Widget::operator=( Widget rhs)
{
swap(rhs);
return *this;
}
note:
后者和前者相比:
1、优点:
将复制动作从“函数本体”移至“函数参数构造阶段”可以提高代码的效率;
2、缺点:
可读性没有那么强。
2、拷贝对象时,不要忘记每一个成分(特别是继承体系中)
(1)拷贝函数包括:拷贝构造函数、拷贝操作符函数。。。。对比两者:
1)拷贝构造函数:
进行直接初始化新构造的一个对象;
2)拷贝操作符函数:
只作用于已经初始化的对象,进行赋值操作。符号右边的对象保持不变。。
(2)继承体系中的拷贝操作
note:由于成员变量通常是private, 所以派生类常常无法直接调用,所以通常调用基类的相应拷贝函数。
e.g
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
:Customer(rhs), priority(rhs. priority) //调用基类的拷贝函数
{
......
}
PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
. .....
Customer::operator=(rhs); //调用基类成分进行赋值
priority = rhs.priority;
return *this;
}