设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 创业者 数据 手机
当前位置: 首页 > 综合聚焦 > 编程要点 > 语言 > 正文

C++重载= 赋值运算符

发布时间:2022-07-05 10:12 所属栏目:51 来源:互联网
导读:在《到底什么时候会调用拷贝构造函数?》一节中,我们讲解了初始化和赋值的区别:在定义的同时进行赋值叫做初始化(Initialization),定义完成以后再赋值(不管在定义的时候有没有赋值)就叫做赋值(Assignment)。初始化只能有一次,赋值可以有多次。 当以
  在《到底什么时候会调用拷贝构造函数?》一节中,我们讲解了初始化和赋值的区别:在定义的同时进行赋值叫做初始化(Initialization),定义完成以后再赋值(不管在定义的时候有没有赋值)就叫做赋值(Assignment)。初始化只能有一次,赋值可以有多次。
 
  当以拷贝的方式初始化一个对象时,会调用拷贝构造函数;当给一个对象赋值时,会调用重载过的赋值运算符。
 
  即使我们没有显式的重载赋值运算符,编译器也会以默认地方式重载它。默认重载的赋值运算符功能很简单,就是将原有对象的所有成员变量一一赋值给新对象,这和默认拷贝构造函数的功能类似。
 
  对于简单的类,默认的赋值运算符一般就够用了,我们也没有必要再显式地重载它。但是当类持有其它资源时,例如动态分配的内存、打开的文件、指向其他数据的指针、网络连接等,默认的赋值运算符就不能处理了,我们必须显式地重载它,这样才能将原有对象的所有数据都赋值给新对象。
 
  仍然以上节的 Array 类为例,该类拥有一个指针成员,指向动态分配的内存。为了让 Array 类的对象之间能够正确地赋值,我们必须重载赋值运算符。请看下面的代码:
  #include <iostream>
  #include <cstdlib>
  using namespace std;
  //变长数组类
  class Array{
  public:
      Array(int len);
      Array(const Array &arr);  //拷贝构造函数
      ~Array();
  public:
      int operator[](int i) const { return m_p[i]; }  //获取元素(读取)
      int &operator[](int i){ return m_p[i]; }  //获取元素(写入)
      Array & operator=(const Array &arr);  //重载赋值运算符
      int length() const { return m_len; }
  private:
      int m_len;
      int *m_p;
  };
  Array::Array(int len): m_len(len){
      m_p = (int*)calloc( len, sizeof(int) );
  }
  Array::Array(const Array &arr){  //拷贝构造函数
      this->m_len = arr.m_len;
      this->m_p = (int*)calloc( this->m_len, sizeof(int) );
      memcpy( this->m_p, arr.m_p, m_len * sizeof(int) );
  }
  Array::~Array(){ free(m_p); }
  Array &Array::operator=(const Array &arr){  //重载赋值运算符
      if( this != &arr){  //判断是否是给自己赋值
          this->m_len = arr.m_len;
          free(this->m_p);  //释放原来的内存
          this->m_p = (int*)calloc( this->m_len, sizeof(int) );
          memcpy( this->m_p, arr.m_p, m_len * sizeof(int) );
      }
      return *this;
  }
  //打印数组元素
  void printArray(const Array &arr){
      int len = arr.length();
      for(int i=0; i<len; i++){
          if(i == len-1){
              cout<<arr[i]<<endl;
          }else{
              cout<<arr[i]<<", ";
          }
      }
  }
  int main(){
      Array arr1(10);
      for(int i=0; i<10; i++){
          arr1[i] = i;
      }
      printArray(arr1);
     
      Array arr2(5);
      for(int i=0; i<5; i++){
          arr2[i] = i;
      }
      printArray(arr2);
      arr2 = arr1;  //调用operator=()
      printArray(arr2);
      arr2[3] = 234;  //修改arr1的数据不会影响arr2
      arr2[7] = 920;
      printArray(arr1);
     
      return 0;
  }
  运行结果:
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  0, 1, 2, 3, 4
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9
 
  将 arr1 赋值给 arr2 后,修改 arr2 的数据不会影响 arr1。如果把 operator=() 注释掉,那么运行结果将变为:
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  0, 1, 2, 3, 4
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  0, 1, 2, 234, 4, 5, 6, 920, 8, 9
  去掉operator=()后,由于 m_p 指向的堆内存会被 free() 两次,所以还会导致内存错误。
  下面我们就来分析一下重载过的赋值运算符。
 
  1) operator=() 的返回值类型为Array &,这样不但能够避免在返回数据时调用拷贝构造函数,还能够达到连续赋值的目的。下面的语句就是连续赋值:
  arr4 = arr3 = arr2 = arr1;
 
 
  2) if( this != &arr)语句的作用是「判断是否是给同一个对象赋值」:如果是,那就什么也不做;如果不是,那就将原有对象的所有成员变量一一赋值给新对象,并为新对象重新分配内存。下面的语句就是给同一个对象赋值:
  arr1 = arr1;
  arr2 = arr2;
 
 
  3) return *this表示返回当前对象(新对象)。
 
  4) operator=() 的形参类型为const Array &,这样不但能够避免在传参时调用拷贝构造函数,还能够同时接收 const 类型和非 const 类型的实参,这一点已经在《C++拷贝构造函数》中进行了详细讲解。
 
  5) 赋值运算符重载函数除了能有对象引用这样的参数之外,也能有其它参数。但是其它参数必须给出默认值,例如:
  Array & operator=(const Array &arr, int a = 100);

(编辑:ASP站长网)

    网友评论
    推荐文章
      热点阅读