Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / C++ 之 重载赋值操作符

下面是一个基类 Bitmap 和派生类 Widget, Widget 中定义了一个私有类型 (private) 指针 pbclass Bitmap { ... };class Widget {...private:Bitmap *pb; // ptr to a heap-allocated object};  当在 Widget 类中重载赋值操作符 "=" 时,需要考虑以下几个方面1  链式赋值 (chain of assignments)  整数 15 首先赋值给 z,得到新值的 z 再赋值给 y,接着得到新值的 y 最后再赋值给 x,如下所示:int x, y, z;x = y = z = 15; // chain of assignments  上述链式赋值相当于如下代码:x = (y = (z = 15));  为了实现链式赋值,函数的返回值须是一个实例自身的引用,也即 *this; 同理,重载其它的复合赋值运算符 (如 +=, -=, *=, /=),也必须在函数结束前返回 *thisWidget& Widget::operator=(const Widget& rhs){delete pb;// stop using current bitmappb = new Bitmap(*rhs.pb);// start using a copy of rhs"s bitmapreturn *this;}2  自赋值  其次要考虑的是,关于自赋值 (self-assigment) 的情况,虽然显式的自赋值并不常见,但潜在的自赋值仍需注意Widgetw;...w = w;// explict assignment to selfa[i] = a[j];// potential assignment to self*px = *py;// potential assignment to self  解决方法是,在函数内加一个 if 语句,判断当前实例 (*this) 和传入的参数 rhs 是不是同一个实例,也即判断是不是自赋值的情况  如果是自赋值,则不作任何处理,直接返回 *this;如果不是自赋值,首先释放实例自身已有内存,然后再分配新的内存,如下所示:Widget& Widget::operator=(cosnt Widget& rhs){if (this == &rhs) return *this; // identity test: if a self-assignment, do nothingdelete pb;pb = new Bitmap(*rhs.pb);return *this;}3  异常安全  上例中,假如在分配内存时,因内存不足或 Bitmap 的拷贝构造函数异常,导致 "new Bitmap" 产生异常 (exception),则 pb 指向的是一个已经被删除的 Bitmap  考虑异常安全,一个方法是先用 new 分配新内容,再用 delete 释放如下代码的内容,如下所示:当 "new Bitmap" 抛出一个异常时,pb 指针并不会改变Widget& Widget::operator=(cosnt Widget& rhs){
if (this == &rhs) return *this; // identity test
Bitmap *pOrig = pb; // remember original pbpb = new Bitmap(*rhs.pb); // make pb point to a copydelete pOrig;// delete the original pbreturn *this;} 如果不考虑效率的问题,那么即使没有对自赋值进行判断的 if 语句,其后面的语句也足以应付自赋值的问题4  拷贝-交换  上例中,因为效率的问题,保留了 if 语句,但实际上,因为自赋值出现的概率很低,所以上述代码看似“高效”,其实并不然  最常用的兼顾自赋值和异常安全 (exception safety) 的方法是 “拷贝-交换” (copy-and-swap),如下所示:Widget& Widget::operator=(const Widget& rhs){Widget temp(rhs);// make a copy of rhs"s datastd::swap(*this, temp); // swap *this"s data with the copy"sreturn *this;} 上述代码使用的是标准库的 swap 函数,当然也可以自定义 swap 函数小结:1) 重载类赋值操作符,首先考虑链式赋值 -- 函数返回 *this,其次考虑自赋值和异常安全 -- “拷贝-交换”2) 被重载的类赋值操作符 "=" 必须定义为成员函数,其它的复合赋值操作符 (如 "+=", "-=" 等) 应该被定义为成员函数参考资料: <Effective C++_3rd> item 10, 11 <剑指 offer> 2.2.1本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-05/131279.htm