1、C++中重载赋值操作函数应该返回什么?

  类重载赋值操作符一般都是作为成员函数而存在的,那函数应该返回什么类型呢?参考内置类型的赋值操作,例如

  int x,y,z;

  x=y=z=15;

  赋值行为相当于x=(y=(z=15)),也就是赋值操作应该返回左操作数的引用,因此,为了和内置类型兼容,类中重载赋值操作符应该返回左操作数的引用,即*this,如下类A的重载赋值操作函数的声明,

  class A{};

  A& A::operator=(const A&);

2、确保重载赋值操作具有良好的行为

  对于赋值操作,首先应该想到的是怎么处理自我赋值,当类包含指针类型的数据时尤为重要,如下所示

  class MyString{

    public:

      ...

      MyString(char *p=NULL);

      MyString& operator=(const MyString&);

    private:

      char *str;

  };

  MyString a("hello");

  MyString b("world");

  a=a;

  我们知道,进行赋值时,首先要释放左操作数的资源,然后再根据右操作数对左操作数进行赋值,赋值操作函数如下所示

  MyString& MyString::operator=(const MyString& rhs){

    delete [] str;

    str=new char[strlen(rhs.str)+1];

    strcpy(str,rhs.str);

    return *this;

  }

  当运行a=a时,会产生意向不到的后果,我们在函数中先释放了左操作数的资源,然后访问右操作数的资源,然后当自我赋值发生时,this==&rhs,也就是说我们先释放了资源,然后又访问了已经被释放的资源的内容,这显然会引起程序崩溃,所以我们需要进行是否是自我赋值操作的验证,修改过后的函数如下

  MyString& MyString::operator=(const MyString& rhs){

    if(this==&rhs)

      return *this;

    delete [] str;

    str=new char[strlen(rhs.str)+1];

    strcpy(str,rhs.str);

    return *this;

  }

  此时,函数虽然处理了自我赋值,但是仍然存在问题,如果new操作失败了怎么办?

  我们已经释放了左操作数的资源,但是在重新分配资源时由于空间不够等原因失败了,如果我们继续对已经释放了的资源进行访问,会产生未定义的结果,赋值操作就不具备异常安全性,对于这个问题有两种解决方案

  第一,调整语句顺序,先保存原来的资源,等重新分配资源完成以后再释放以前的资源

  MyString& MyString::operator=(const MyString& rhs){

    char *pTemp=str;

    str=new char[strlen(rhs.str)+1];

    strcpy(str,rhs.str);

    delete [] pTemp;

    return *this;

  }

  这段代码也能够处理自我赋值,但是必须执行完函数中的所有复制、分配和释放操作,如果自我赋值发生的概率比较高,我们也可以将测同语句放进该函数。

  第二、采用copy and swap技术

  MyString& MyString::operator=(const MyString& rhs){

    if(this!=&rhs){

      MyString temp(rhs);

      char *pTemp=str;

      str=temp.str;

      temp.str=pTemp;

    }

    return *this;

  }

  这种技术赋值的是指针而不是为对象重新分配资源,我们在if语句内重新构造了一个新的临时对象,然后将临时对象的str和本类对象的str进行交换,当程序执行到if语句外时,临时对象自动调用析构函数,释放自己的资源,此时临时对象所持有的资源就是原来this所持有的资源,该资源得以释放,而现在this所持有的资源是rhs所持有的资源,即此时rhs和this中的str所指向的是同一块空间。

3、复制对象时切勿忘记复制其每一个元素

  对于有继承关系的类,在对其派生类编写复制控制的函数时,由于派生类无法访问基类中的私有成员,所以在派生类的重载操作符函数中,需要首先调用其基类的赋值操作符函数对派生类中的基类成员进行赋值,然后再对派生类中的特有成员进行赋值。

最新文章

  1. 一台主机上安装多个Tomcat
  2. SQL 数据分页查询
  3. IOS-指定返回Modal的控制器presentViewController
  4. Mybatis 后台SQL不输出
  5. linux下使用线程锁互斥访问资源
  6. 父类构造函数中的this指针在子类构造对象后,这个this指针指向什么
  7. Activity的四种launchMode 详细分析
  8. Hacker(七)----黑客常用术语和DOS命令
  9. JVM学习之内存分配一
  10. hdu4521 小明系列的问题——小明序列(LIS变种 (段树+单点更新解决方案))
  11. 读书笔记 effective c++ Item 16 成对使用new和delete时要用相同的形式
  12. c++ 构造函数以及explicit 关键字的使用
  13. Android事件传递机制详解及最新源码分析——View篇
  14. Android中Activity和Service的数据通讯
  15. 字符编辑技术C语言实现
  16. re模块的方法总结
  17. 调用pymysql模块操作数据库
  18. arp断网攻击
  19. python学习线路
  20. MVC生成页码选择器返回HTML代码

热门文章

  1. 深搜(DFS),回溯,Fire Net
  2. 围绕react衍生出来的思考
  3. PHP处理Excel
  4. Intellij idea创建(包、文件)javaWeb以及Servlet简单实现(Tomcat)
  5. intellig idea中jsp或html数据没有自动保存和更换字体
  6. Android学习笔记_54_自定义 Widget (Toast)
  7. bootstrap-table表格导出
  8. java使用JSCH连接FTP(Linux服务器)上传文件到Linux服务器
  9. Python基础—09-文件操作
  10. javascript 中数组的创建 添加 与将数组转换成字符串 页面三种提交请求的方式