当前位置:   article > 正文

C++值赋值运算符重载

C++值赋值运算符重载

C++值赋值运算符重载中存在一些坑点,这里总结一下。

C++值赋值运算符重载基础

C++值赋值运算符重载的格式是这样的:

类名 & operator(const 类名 & 对象名){
    拷贝体
}
  • 1
  • 2
  • 3
  • 初始化和赋值的区别

    • 在定义的同时进行赋值叫做初始化,定义完成以后再赋值(不管在定义的时候有没有赋值)就叫做赋值(Assignment)。初始化只能有一次,赋值可以有多次。
    • 赋值运算符重载是用一个已经存在的对象赋值给另一个已经存在的对象,而拷贝构造函数是用一个已经存在的对象去创建另一个不存在的对象,这两者是不一样的。
  • 当以拷贝的方式初始化一个对象时,会调用拷贝构造函数;当给一个对象赋值时,会调用重载过的赋值运算符。

赋值运算符注意点

赋值运算符

对于简单的类,默认的赋值运算符(若没有显示定义赋值运算符重载,则编译器会自动生成一个默认的赋值运算符重载)一般就够用了,也没有必要再显式地重载它。但是当类持有其它资源时,例如动态分配的内存、打开的文件、指向其他数据的指针、网络连接等,默认的赋值运算符就不能处理了,必须显式地重载它:

编译器自动生成默认赋值运算符重载同样是等位赋值,也就是浅拷贝会造成内存泄漏和重析构。如下所示:

class A{
private:
    char *c;
public:
    A(){
        c = new char[100];
    }
};

int main(){
    A a;
    A b;
    b  = a;   //此时就是调用的赋值运算符重载
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

那么对象a和对象b都已经存在,也都分别开辟了空间,不只是为对象本身开辟了空间,也同样为成员变量c开辟了100的空间大小,像图中所示:

在这里插入图片描述

然后因为:

b = a;
  • 1

这么一句代码的关系,就变成了这样:

在这里插入图片描述

那么b同样也指向了a对象为c开辟的空间地址,那么b.c便无法释放,那么这段内存空间就会造成内存泄漏,当释放a和b时,a.c又被释放了两次,就是重析构,这就是编译器自动生成的赋值运算符重载的弊端。

要避免上面出现的两种情况,那么就要自定义赋值运算符重载,使用深拷贝。

A & operator=(const A & other){
    if(this == &other)  // &表示取地址
        return *this;
    delete []c;
    int len = strlen(other.c);
    this->c = new char[len + 1];
    strcpy(this->c, other.c);
    return *this;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 要想不避免内存泄漏,就要在赋值之前,先把自己为成员变量开辟的空间释放掉。
  • 要想避免重析构,就要再根据要复制的对象的长度再开辟一段自己的内存空间,再重新赋值就可以了。
  • 为了避免自赋值,把自己释放掉,就无从复制的原因,要先判断是否是自赋值。同时自赋值也会造成循环调用赋值运算符,最后进入死循环。

返回值

return *this表示返回当前对象(新对象)。 这样就可以实现连等操作:

A a, b, c;
a = b = c;
(a = b) = c;
  • 1
  • 2
  • 3

上面两种连等都是可以的,但如果赋值运算符重载的返回类型前面加了const,也就是这样:

const A& operator=(const A & a){}
  • 1

再执行连等就会报错,因为c赋给了可以改变的a对象,这是不允许的,所以赋值运算符重载的返回类型一定要注意要不要加const

参考文章

https://blog.csdn.net/maoliran/article/details/51526459

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/406190
推荐阅读
相关标签
  

闽ICP备14008679号