首页 > 编程语言 >C/C++ 拷贝构造函数 | 赋值构造函数 | 移动构造函数 | 移动赋值构造函数

C/C++ 拷贝构造函数 | 赋值构造函数 | 移动构造函数 | 移动赋值构造函数

时间:2024-08-17 18:55:35浏览次数:12  
标签:构造函数 对象 ClassName MyClass 移动 data 赋值

文章目录

前言

C++中关于一个对象的构造,就有很多讲究。
其中最常用的可能就是拷贝构造函数和赋值构造函数。
后面的移动相关的就用的很少,每次面试的时候会刷一下面经,突击一下概念,工作中用到少了,久而久之就忘了。

这篇文章就对与一个对象的几种构造方式做一个总结。


1. 拷贝构造函数 (Copy Constructor)

定义:拷贝构造函数用于创建一个新对象,该新对象是现有对象的副本。它的函数签名通常是:
ClassName(const ClassName& other);

作用:当你使用一个对象初始化另一个对象时,编译器会调用拷贝构造函数。例如:
ClassName obj1;
ClassName obj2 = obj1; // 调用拷贝构造函数

实现:如果类中包含动态分配的资源(如指针),需要自定义拷贝构造函数以确保深拷贝:

class MyClass {
public:
    int* data;

    MyClass(int value) : data(new int(value)) {}

    // 拷贝构造函数
    MyClass(const MyClass& other) : data(new int(*other.data)) {}

    ~MyClass() { delete data; }
};

2. 赋值构造函数 (Copy Assignment Operator)

定义:赋值构造函数用于将一个已存在的对象的内容赋值给另一个已存在的对象。其函数签名通常是:
ClassName& operator=(const ClassName& other);

作用:当你用一个对象的值来赋值给另一个已存在对象时,编译器会调用赋值构造函数。例如:
ClassName obj1;
ClassName obj2;
obj2 = obj1; // 调用赋值构造函数

实现:和拷贝构造函数类似,赋值构造函数也需要处理动态资源,以避免资源泄漏或浅拷贝的问题:

class MyClass {
public:
    int* data;

    MyClass(int value) : data(new int(value)) {}

    // 拷贝构造函数
    MyClass(const MyClass& other) : data(new int(*other.data)) {}

    // 赋值构造函数
    MyClass& operator=(const MyClass& other) {
        if (this == other) return *this; // 自赋值检查
        delete data;
        data = new int(*other.data);
        return *this;
    }

    ~MyClass() { delete data; }
};

拷贝构造函数和赋值构造函数对比:
概念理解上:
拷贝构造是创建一个新对象,新对象是通过一个已存在的对象进行初始化,新对象的内容是已存在对象的副本。
赋值构造函数是对一个已经创建好的对象,用另一个已经存在的对象进行内容赋值。

使用形式上:

拷贝构造
ClassName obj1;
ClassName obj2 = obj1; // 调用拷贝构造函数
当然一般我们这样用:ClassName obj2(&obj1);

赋值构造函数
ClassName obj1;
ClassName obj2;
obj2 = obj1; // 调用赋值构造函数
这里和上面构造不同的地方在于,obj2先创建了,再进行赋值。虽然都是可以用=的方式进行初始化。
而且,赋值构造函数,其实是重载了运算符=,所以这个就是我们自定义的一种赋值运算,这个赋值运算
刚好又给一个对象进行初始化,所以叫做赋值构造函数。


讲移动构造函数、移动赋值构造函数的概念之前,我们先要明白一个概念,
什么是左值和右值
就我目前的理解来说,我认为

左值:在内存中分配了内存进行存放的变量/对象/…等;它是有实际的存放地址的;
它一般位于运算符左侧,比如int a=1,a就是左值,因为它是一个内存中的变量,有实际的内存地址,同时在运算符左侧。
右值:属于一种临时变量,在脱离作用域后自动释放。没有实际存放的地址;
它一般位于运算符左侧,比如int a=1,1就是右值,因为它不是一个内存中的变量,没实际的内存地址,同时在运算符右侧。
还有一些我们的中间变量,比如int a=b+c;假如这里b和c都是声明的int类型变量,但是b+c得到的值其实是一个右值,因为它只是一个中间的临时变量。

左值通常表示对象的命名变量,可以用于取地址(有持久存储)。
右值通常表示临时对象或常量,不能用于取地址(无持久存储)。右值引用允许将资源从一个对象“移动”到另一个对象,而不是进行深拷贝。

3. 移动构造函数 (Move Constructor)

定义:移动构造函数用于将资源从一个临时对象(右值)转移到新创建的对象中。其函数签名通常是:
ClassName(ClassName&& other) noexcept;

作用:当一个对象被移动而不是拷贝时(例如,返回一个对象或使用 std::move),编译器调用移动构造函数。例如:
ClassName obj1;
ClassName obj2 = std::move(obj1); // 调用移动构造函数

实现:移动构造函数通常会将源对象的资源直接转移给新对象,然后将源对象的资源指针置为 nullptr:

class MyClass {
public:
    int* data;

    MyClass(int value) : data(new int(value)) {}

    // 移动构造函数
    MyClass(MyClass&& other) noexcept : data(other.data) {
        other.data = nullptr;
    }

    ~MyClass() { delete data; }
};

4. 移动赋值构造函数 (Move Assignment Operator)

定义:移动赋值构造函数用于将一个临时对象(右值)的资源转移到另一个已存在的对象中。其函数签名通常是:
ClassName& operator=(ClassName&& other) noexcept;

作用:当你将一个临时对象的资源赋值给一个已存在的对象时,编译器会调用移动赋值构造函数。例如:
ClassName obj1;
ClassName obj2;
obj2 = std::move(obj1); // 调用移动赋值构造函数

实现:移动赋值构造函数通常需要释放当前对象的资源,并转移源对象的资源,然后将源对象的资源指针置为 nullptr:

class MyClass {
public:
    int* data;

    MyClass(int value) : data(new int(value)) {}

    // 移动构造函数
    MyClass(MyClass&& other) noexcept : data(other.data) {
        other.data = nullptr;
    }

    // 移动赋值构造函数
    MyClass& operator=(MyClass&& other) noexcept {
        if (this == &other) return *this; // 自赋值检查
        delete data; // 释放当前资源
        data = other.data; // 转移资源
        other.data = nullptr;
        return *this;
    }

    ~MyClass() { delete data; }
};

移动构造与非移动构造对比
概念理解上:
这个我们对比一下拷贝构造函数和赋值构造。
移动的概念就是,给数据的对象是一个临时变量,而非移动构造是一个具体的对象。
移动构造就是把一个临时对象的值通过std::move 移动到新对象
移动赋值构造就是把一个临时对象的值通过std::move 移动到已存在对象
所以其实拷贝构造和赋值构造最大的区别就在于被构造的对象是不是已存在。

使用形式上:
移动的这种构造,都需要std::move这个函数。
同时需要用到两个引用符&&,这里两个&是因为传的是引用参数。
关于&的个数问题,这里做一个解释
左值引用用一个&表示(T&),可以绑定到左值。
右值引用用两个&表示(T&&),可以绑定到右值。


总结

1.拷贝构造函数 用于创建一个新对象作为现有对象的副本。
2.赋值构造函数 用于将一个对象的值赋给另一个已经存在的对象。
3.移动构造函数 用于将资源从一个临时对象转移到新对象中,避免不必要的资源复制。
4.移动赋值构造函数 用于将临时对象的资源转移到一个已经存在的对象中,并释放现有对象的资源。

标签:构造函数,对象,ClassName,MyClass,移动,data,赋值
From: https://blog.csdn.net/Edwinwzy/article/details/141230913

相关文章

  • 基于nodejs+vue面向移动端的房屋租赁系统的设计与实现[程序+论文+开题]-计算机毕业设
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着城市化进程的加快和人口流动性的增强,房屋租赁市场日益繁荣,成为解决居民居住需求的重要途径。然而,传统的房屋租赁方式往往存在信息不对称、效率低下、交......
  • 基于nodejs+vue面向移动端的线上作业系统的设计与实现App[程序+论文+开题]-计算机毕业
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和智能手机的普及,教育领域正经历着深刻的变革。传统的作业提交与批改方式逐渐显现出效率低下、反馈不及时等问题,难以满足现代教育的......
  • 前端css动画水平移动,垂直移动,对角线移动transform
    水平移动:transform:translateX(100px);沿着x轴向右移动100px,向左-100px 垂直移动:transform:translateY(100px);沿着Y轴向上移动100px,向下就是-100px 对角线移动:transform:translate(100px,100px);     对应x轴,y轴坐标<!DOCTYPEhtml><htmllang="en"......
  • 0237-RLTK-控制角色移动
    环境Time2022-11-29WSL-Ubuntu22.04RLTK0.8.7前言说明参考:https://bfnightly.bracketproductions.com/rustbook目标使用键盘来控制角色在窗口中进行移动。Component#[derive(Component)]structPosition{x:i32,y:i32,}#[derive(Component)]struc......
  • JS中构造函数继承问题注意事项总结
    在JavaScript中,继承是通过原型链来实现的。当你想要创建一个子类(比如Student)继承一个父类(比如Person)时,通常会使用Object.create来创建Student的原型对象。这背后有一些重要的原因:1.共享与独立性当你执行Student.prototype=Person.prototype时,Student的原型......
  • 免费【2024】springboot 哈尔滨中心医院用户移动端的设计与实现
    博主介绍:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌技术范围:SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数......
  • ToDesk远程控制移动端使用教程!这些功能必用!
    不得不说,ToDesk的移动端还挺全面,在界面,文件传输等使用操作上都有了新变化,还增加了了免费的标注功能。小社长身先士卒更新了一波,用下来发现ToDesk移动端真香!接下来让咱们启动新版ToDeskApp,一起来挖掘这些新功能有多好使吧~全新使用界面,优化远程步骤相比之前的移动端页面,新版的......
  • C# WindowForm界面初探,窗体访问,绑定数据源,重载构造函数
    今日份主要内容C#WindowForm界面初探Winform项目模板,目录解析窗体对象控件对象界面设计基础1.控件?控件的本质是类,控件是构建用户界面(UserInterface)的基础,通过控件组合设计出符合需求的界面效果。相当于html的标签。基本要求:界面效果,布局交互(事件,委托)2.学习控件......
  • SciTech-BigDataAIML-LLM-Transformer Series-统计模型和大量数据 + MI移动互联+IoT万
    词汇MI(MobileInternet):移动互联网IoT(InternetofThings):万物互联网WE(WordEmbedding):词嵌入PE(PositionalEncoding):位置编码统计模型和大数据的保障和源头是"MI"和"IoT"。1真正"改革生产生活习惯"的是"国家政策"与"政府"。新经济的产生是以“改革生产生活......
  • [已解决] 使用向日葵远程控制在Ubuntu系统上控制Minecraft存在鼠标移动视角异常
    省流:使用Ctrl+Alt+Enter将当前鼠标指针切换到被控鼠标方指针。问题描述在使用向日葵远程控制连接到我的远程Ubuntu系统中游玩Minecraft时,发现鼠标视角的移动有问题。具体表现为,鼠标可以点击菜单、按钮等,也可以点击选择物品、左键摧毁物品、右键使用物品,然而移动鼠标......