operator 中处理”自我赋值“

operator=操作符缺省情况下返回引用——TYPE& TYPE::operator=(const TYPE&),原因很简单,operator=返回引用的理由是使你能在一个语句中连接多个赋值。

  1. int x, y, z;
  2. x = y = z = ; // chain of assignments

赋值采用右结合律,上面的代码被编译器解释为:

  1. x = (y = (z = ));

在编译过程中,赋值是右结合的。说白了就是如果你想要玩一下多个赋值,operator=返回的东西必须是右(rhs)赋值。除了返回对对象自身的引用还能有什么呢?这就是为什么operator=最后一行总是返回对this的引用:

  1. class Widget {
  2. public:
  3.   ...
  4.   Widget& operator=(const Widget& rhs) // return type is a reference to
  5.   { // the current class
  6.   ...
  7.   return *this; // return the left-hand object
  8.   }
  9.   ...
  10. };

再来看自我赋值,即对象被赋值给自己,假设建立一个class用来保存一个指针指向一块动态分配的bitmap

  1. class Bitmap { ... };
  2. class Widget {
  3.   ...
  4.   private:
  5.   Bitmap *pb; // ptr to a heap-allocated object
  6. };

下面是operator=代码,表面上看合理,但自我赋值时并不安全。

  1. Widget&
  2. Widget::operator=(const Widget& rhs) // unsafe impl. of operator=
  3. {
  4.   delete pb; // stop using current bitmap
  5.   pb = new Bitmap(*rhs.pb); // start using a copy of rhs’s bitmap
  6.   return *this; // see Item 10
  7. }

如果rhs与*this指向同一对象,第一句的delete pb就销毁了bitmap中调用的rhs.pb,这一问题的解决方案是copy and swap:

  1. class Widget {
  2. ...
  3. void swap(Widget& rhs); // exchange *this’s and rhs’s data;
  4. ... // see Item29 for details
  5. };
  6. Widget& Widget::operator=(const Widget& rhs)
  7. {
  8.   Widget temp(rhs); // make a copy of rhs’s data
  9.   swap(temp); // swap *this’s data with the copy’s
  10.   return *this;
  11. }

它先将rhs做一个复本,由这个复本与this交换数据来达到目的。

复制对象时确保复制对象内每个成员变量

类customer如下所示:

  1. void logCall(const std::string& funcName); // make a log entry
  2. class Customer {
  3. public:
  4.   ...
  5.   Customer(const Customer& rhs);
  6.   Customer& operator=(const Customer& rhs);
  7.   ...
  8. private:
  9.   std::string name;
  10. };
  11. Customer::Customer(const Customer& rhs)
  12.   : name(rhs.name) // copy rhs’s data
  13. {
  14.   logCall("Customer copy constructor");
  15. }
  16. Customer& Customer::operator=(const Customer& rhs)
  17. {
  18.   logCall("Customer copy assignment operator");
  19.   name = rhs.name; // copy rhs’s data
  20.   return *this; // see Item 10
  21. }

这个程序完全正确,但当在类中加入一个成员变量,我们同时也要在复制运算中加入相应的变量复制。

  1. class Date { ... }; // for dates in time
  2. class Customer {
  3. public:
  4.   ... // as before
  5. private:
  6.   std::string name;
  7.   Date lastTransaction;
  8. };

如果忘记修改operator=函数,编译器不会提醒你,从而造成潜在的漏洞。

再来看派生类复制的情况

  1. class PriorityCustomer: public Customer { // a derived class
  2. public:
  3.   ...
  4.   PriorityCustomer(const PriorityCustomer& rhs);
  5.   PriorityCustomer& operator=(const PriorityCustomer& rhs);
  6.   ...
  7. private:
  8.   int priority;
  9. };
  10. PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
  11. : priority(rhs.priority)
  12. {
  13.   logCall("PriorityCustomer copy constructor");
  14. }
  15.  PriorityCustomer&
  16. PriorityCustomer::operator=(const PriorityCustomer& rhs)
  17. {
  18.   logCall("PriorityCustomer copy assignment operator");
  19.   priority = rhs.priority;
  20.   return *this;
  21. }
  1. PriorityCustomer好像是完全复制了成员变量,但每个PriorityCustomer类都还包含着基类的成员变量未被复制,PriorityCustomer类中的customer成分被不带实参的customer构造函数初始化,customer成员变量初始化为缺省的值。我们所要做的是提供一个第三方的函数来调用基类的复制函数。

注意两个错误用法:1、令copy assignment操作符调用copy构造函数是错误的,因为在这就像试图构造一个已存在的对象。2、令copy构造函数调用copy assignment操作符同样是错误的。构造函数用来出事后对象,而assignment操作符只实行与已初始化的对象身上。对一个尚未构造好的对象赋值,就像在一个尚未初始化的对象身上做“z只对已初始化对象才有意义”的事意义。

effective c++:对象的赋值运算的更多相关文章

  1. Effective C++ —— 构造/析构/赋值运算(二)

    条款05 : 了解C++默默编写并调用哪些函数 编译器可以暗自为class创建default构造函数.copy构造函数.copy assignment操作符,以及析构函数. 1. default构造函 ...

  2. Effective C++ -- 构造析构赋值运算

    05.了解C++默默编写并调用哪些函数 编译产生的析构函数时non-virtual,除非这个类的基类析构函数为virtual 成员变量中有引用和const成员时,无法自己主动生成copy assign ...

  3. 《Effective C++》第2章 构造/析构/赋值运算(2)-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  4. 《Effective C++》第2章 构造/析构/赋值运算(1)-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  5. Effective C++ 笔记二 构造/析构/赋值运算

    条款05:了解C++默默编写并调用哪些函数 编译器默认声明一个default构造函数.一个copy构造函数.一个copy assignment操作符和一个析构函数.这些函数都是public且inlin ...

  6. Effective C++: 02构造、析构、赋值运算

    05:了解C++默默编写并调用哪些函数 1:一个空类,如果你自己没声明,编译器就会为它声明(编译器版本的)一个copy构造函数.一个copy assignment操作符和一个析构函数.此外如果你没有声 ...

  7. C++中的构造函数,拷贝构造函数和赋值运算

    关于C++中的构造函数,拷贝构造函数和赋值运算,以前看过一篇<高质量C++/C编程指南>的文章中介绍的很清楚,网上能搜索到,如果想详细了解这方面的知识可以参看一下这篇文章. 常见的给对象赋 ...

  8. js赋值运算的理解

    简介 js引擎由于为了效率,很多时候的非直接量赋值都不是copy一份在赋值给新的变量,而是一个引用 ps:直接量:直接值数字字符串等 为什么使用len = doms.length; 里的len效率要比 ...

  9. Effective C++(11) 自我赋值(a=a)时会发生什么?

    问题聚焦: 自我赋值看似有点愚蠢的行为,其实总会发生的 首先:它是合法的, 其次,它不一定是安全的, 再次,它有时候不是那么明显. 先看一个Demo class Widget { ... }; Wid ...

随机推荐

  1. 自动化测试LoadRunner

    这个地址应该比较的好下载,以前找的地址都是需要输入一些相关的信息.这个只需要有一个HP的注册账号就可下载,记下来.以备后用: 下载地址: http://www8.hp.com/us/en/softwa ...

  2. nodetree中 前面复选框禁用插件

    nodetree中 前面复选框的去掉插件 extendTreeCheck.js /** * tree方法扩展 * 作者:小雪转中雪 */ $.extend($.fn.tree.methods, { / ...

  3. minimum-moves-to-equal-array-elements

    https://leetcode.com/problems/minimum-moves-to-equal-array-elements/ package com.company; import jav ...

  4. 跨域利器JSONP(转)

    何为跨域?何为JSONP?JSONP技术能实现什么?是否有必要使用JSONP技术? 跨域 就是由于JavaScript同源策略的限制,使得a.com域名下的js无法操作b.com或c.a.com域名下 ...

  5. RAD DELPHI XE5的android开发环境配置

    RAD XE5 支持本地化跨平台编译(IOS,OS-X,WIN 64,WIN32,ANDROID) 对于android的开发环境,XE5支持模拟器,和真机设备两种模式: 1. 模拟器:(支持4.0.3 ...

  6. [ionic开源项目教程] - 第12讲 医疗模块的实现以及Service层loadMore和doRefresh的提取封装

    关注微信订阅号:TongeBlog,可查看[ionic开源项目]全套教程. 这一讲主要实现tab2[医疗]模块,[医疗]模块跟tab1[健康]模块类似. [ionic开源项目教程] - 第12讲 医疗 ...

  7. div中文字水平和垂直居中的css代码

    HTML元素 <div>水平垂直居中</div> css样式 div{ width:200px;height:200px; /*设置div的大小*/ border:1px so ...

  8. MVC 简单发送邮件示例

    没啥好说的 直接上代码 @{ try { WebMail.SmtpServer = "smtp.qq.com";//SMTP邮件服务器 WebMail.SmtpPort = ;// ...

  9. HDU 1251 统计难题【字典树】

    题意:中文题--跟着模板敲的--第一棵字典树--@_@ #include<iostream> #include<cstdio> #include<cstring> ...

  10. 实现图片大小的自动控制( 图片大小控制CSS代码)

    图片大小控制CSS代码 将以下代码放到你的样式表文件中即可实现图片大小的自动控制. /*图片大小控制CSS By Tekin */img,a img{border:0;margin:0;padding ...