关于“operator=”

一、中心思想

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;

}






  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值