当前位置: 首页 > article >正文

【C++指南】类和对象(五):类的默认成员函数——全面剖析 赋值运算符重载函数

           💓 博客主页:倔强的石头的CSDN主页 

           📝Gitee主页:倔强的石头的gitee主页

            ⏩ 文章专栏:《C++指南》

                                  期待您的关注

47f09392526c71b5885ec838a3ea7ffe.gif

 

目录

 引言

🍃概念

🍃语法

🍃作用

🍃特点(重要)

🍃规则

🍃默认赋值运算符重载函数的行为

🍃需要自己实现的情况

🍃如何自己实现

示例代码解析

结语


 

  C++类和对象系列文章,可点击下方链接阅读:

【C++指南】类和对象(一):类和对象的定义和使用 基础讲解_c++ 类对象的使用-CSDN博客

【C++指南】类和对象(二):类的默认成员函数——全面剖析 :构造函数-CSDN博客

【C++指南】类和对象(三):类的默认成员函数——全面剖析: 析构函数-CSDN博客

【C++指南】类和对象(四):类的默认成员函数——全面剖析 拷贝构造函数-CSDN博客

【C++指南】类和对象(五):类的默认成员函数——全面剖析 赋值运算符重载函数-CSDN博客

 

 

 引言

在C++中,类可以定义自己的赋值运算符(=)来控制对象之间的赋值操作。这被称为赋值运算符的重载。通过重载赋值运算符,我们可以实现更复杂或特定的赋值逻辑,比如深拷贝、资源管理等。

赋值运算符重载是⼀个默认成员函数,用于完成两个已经存在的对象直接的拷贝赋值

这⾥要注意跟拷贝构造区分,拷贝构造用于⼀个对象拷贝初始化给另⼀个要创建的对象。

运算符重载没搞懂?

没关系,贴心的我已经为你准备好了配套文章

点击下方链接阅读:

【C++指南】运算符重载详解-CSDN博客

🍃概念

赋值运算符重载函数是一种特殊的成员函数,它允许我们定义对象赋值时发生的操作。默认情况下,编译器会为类提供一个默认的赋值运算符,但它只进行浅拷贝(shallow copy)。在某些情况下,我们需要实现自己的赋值运算符重载函数以确保正确的行为。

🍃语法

赋值运算符重载函数的声明和定义如下:

ClassName& operator=(const ClassName& other);
这个函数返回对调用对象的引用,并接受一个同类型对象的常量引用作为参数。

🍃作用

赋值运算符重载函数的主要作用是:

  1. 深度拷贝:确保在赋值过程中,对象的所有动态分配的资源都被正确复制。
  2. 资源管理:防止内存泄漏、资源重复释放等问题。
  3. 自定义行为:允许在赋值时执行额外的逻辑,如更新日志、检查自赋值等。

 

🍃特点(重要)

  • 返回引用函数返回调用对象的引用,以便支持连续赋值。(这一点也是为了与运算符的原用法相符。返回值建议写成当前类类型引⽤,引⽤返回可以提⾼效率,有返回值⽬的是为了⽀持连续赋 值场景)
  • 参数类型:参数为常量引用,以避免不必要的拷贝和修改。
  • 自赋值检测:需要处理 self-assignment(自赋值)的情况,以避免重复释放资源或导致未定义行为。
  • 成员函数:规定必须重载为成员函数

🍃规则

  • 返回类型:返回当前对象的引用。
  • 参数类型:参数应为常量引用,以避免拷贝和修改。
  • 异常安全性:确保在异常发生时,对象处于有效状态。
  • 自赋值检测:通过比较对象地址来检测自赋值。

🍃默认赋值运算符重载函数的行为

  • 编译器生成的默认赋值运算符,对内置类型成员变量会完成值拷贝/浅拷贝(⼀个字节⼀个字节的拷贝),对于包含指针成员的类,这可能导致资源泄露或重复释放的问题。
  • 对⾃定义类型 成员变量会调⽤他的拷贝构造

 浅拷贝/深拷贝没搞懂?

没关系,贴心的我依然为你准备好了配套文章

点击下方链接阅读:

【C++指南】C++中的浅拷贝与深拷贝:深入剖析-CSDN博客

 

🍃需要自己实现的情况

  • 包含动态分配资源的类:如指针、动态数组、智能指针等。
  • 需要自定义赋值逻辑:如记录赋值操作、更新日志等。

这⾥还有⼀个小技巧:

一般情况下,⼀个类如果显式实现 了析构并释放资源,那么他就需要显式写赋值运算符重载,否则就不需要 

 

🍃如何自己实现

下面是一个简单的示例,演示如何为包含动态分配数组的类实现赋值运算符重载函数:

#include <iostream>  
#include <cstring>  // For std::strcpy  

class MyClass {
private:
    char* data;
    size_t size;

public:
    //构造
    MyClass(const char* str = "") {
        size = std::strlen(str) + 1;  // +1 for null terminator  
        data = new char[size];
        std::strcpy(data, str);
    }

    // 拷贝构造
    MyClass(const MyClass& other) {
        size = other.size;
        data = new char[size];
        std::strcpy(data, other.data);
    }

    // 赋值运算符重载
    MyClass& operator=(const MyClass& other) {
        //自赋值检测
        if (this == &other) {
            return *this;
        }

        //释放现有资源  
        delete[] data;

        // 分配新资源并复制数据 
        size = other.size;
        data = new char[size];
        std::strcpy(data, other.data);

        return *this;
    }

    //析构
    ~MyClass() {
        delete[] data;
    }

    // 打印数据  
    void display() const {
        std::cout << data << std::endl;
    }
};

int main() {
    MyClass obj1("Hello");
    MyClass obj2("World");

    obj1.display();  // Output: Hello  
    obj2.display();  // Output: World  

    obj1 = obj2;

    obj1.display();  // Output: World  

    return 0;
}

示例代码解析

  1. 构造函数:分配内存并复制字符串。
  2. 拷贝构造函数:实现深拷贝,避免浅拷贝导致的资源问题。
  3. 赋值运算符重载
    • 自赋值检测:通过比较地址来避免自赋值。
    • 释放现有资源:避免内存泄漏。
    • 分配新资源并复制数据:确保对象状态正确。
  4. 析构函数:释放分配的内存,防止内存泄漏。

结语

通过重载赋值运算符,我们可以更好地控制对象间的赋值过程,尤其是在涉及资源管理或需要特殊处理的情况下。理解并正确实现赋值运算符对于编写健壮、高效的C++代码至关重要。

 

 


http://www.kler.cn/a/371155.html

相关文章:

  • C++ 整型大数运算(大整数运算)项目
  • 关键词排名技巧实用指南提升网站流量的有效策略
  • 如何将原本打开Edge呈现出的360浏览器,更换成原本的Edge页面或者百度等其他页面
  • Python 学习 DAY1
  • C++——NetWork
  • 区块链系统控制台Console的安装与运维
  • Spring+SpringMVC+SpringJDBC搭建web项目实现商品查询
  • 什么?Flutter 又要凉了? Flock 是什么东西?
  • STM32F1学习——EXTI
  • C++中如何获取时间并格式化为字符串?
  • 【域攻防】超级黄金票据食用指南
  • 快速遍历包含合并单元格的Word表格
  • 信息安全数学基础(33)群
  • 使用DeepLabV3实现植叶病害检测
  • 蓝桥杯基本算法~~~一维/二维前缀和问题
  • 【ComfyUI】手动安装部署ComfyUI的运行环境
  • QML旋转选择器组件Tumbler
  • 第十一章 Shiro会话管理和加密
  • 《Web性能权威指南》-WebRTC-读书笔记
  • 【GL08】STM32--ADC/DAC
  • spring-boot(入门)
  • 深入探索:深度学习在时间序列预测中的强大应用与实现
  • 编程解决有趣的智力题
  • 17、电话号码的字母组合-cangjie
  • 中阳智能投资系统:量化科技引领未来投资之路
  • gbase8s之spring框架用druid中间件报语法错误