C++之浅拷贝、深拷贝、拷贝构造函数、拷贝赋值运算符、自定义的深拷贝函数应用总结(二百二十九)

news2024/11/25 4:55:28

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

1.前言

本篇目的:理解C++之拷贝类对象到this指针应用。

  1. 浅拷贝(Shallow Copy):
    浅拷贝是指简单地复制对象的成员变量的值。在浅拷贝中,只复制指针或基本数据类型的值,而不会创建新的动态内存或复制指针所指向的数据。这导致多个对象共享相同的内存,可能引发潜在的问题,例如内存释放或修改数据时的冲突。

  2. 深拷贝(Deep Copy):
    深拷贝是指复制整个对象及其动态分配的内存。在深拷贝中,会创建一个新的对象,并为新对象的成员变量分配独立的内存,以复制原始对象的数据。这样可以确保每个对象拥有独立的内存空间,从而避免了共享数据的问题。

  3. 拷贝构造函数(Copy Constructor):
    拷贝构造函数是类的特殊成员函数,用于创建一个新对象,该新对象是通过复制现有对象的数据来初始化的。拷贝构造函数通常以引用形式接受一个同类型的对象作为参数,并从参数对象中复制数据到新对象。拷贝构造函数常用于对象的初始化、传递对象给函数或返回对象时进行复制操作。

  4. 拷贝赋值运算符(Copy Assignment Operator):
    拷贝赋值运算符是另一个特殊成员函数,用于将一个对象的数据复制给另一个已存在的对象。通常以赋值运算符(=)表示,并在函数体内执行适当的数据复制操作。拷贝赋值运算符允许对象之间完成数据的拷贝和替换,使一个对象能够取代另一个对象的数据。

  5. 自定义的深拷贝函数(Custom Deep Copy Function):
    自定义的深拷贝函数是用户自行编写的函数,用于实现对于类对象的深度复制。这种函数通常通过自己分配新的内存,并复制原始对象的成员变量内容到新分配的内存中。自定义的深拷贝函数可以在没有默认的拷贝构造函数或拷贝赋值运算符的情况下,实现深度复制。

  6. 通过指针进行拷贝(Copy by Pointer):
    通过指针进行拷贝是一种在类的拷贝操作中,复制指针本身的值,而不是复制指针指向的数据。这意味着多个指针将指向相同的数据,从而可能导致数据修改引起的冲突。这种方式通常不是推荐的拷贝方式,除非确保指向的数据不会在拷贝对象之间发生改变。

  7. 移动语义(Move Semantics):
    移动语义是一种优化技术,用于在对象转移时避免不必要的内存复制。通过使用移动构造函数和移动赋值运算符,对象的资源(如动态分配的内存)可以在转移后被接收方使用,而不需要进行复制。这在提高程序性能和减少资源占用方面是有益的。

2.应用实例

v1.0 浅拷贝

#include <iostream>

class MyClass {
public:
    int value;

    MyClass(int val = 0) : value(val) {}

    void printValue() const {
        std::cout << "Value: " << value << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = obj1; // 浅拷贝

    obj1.printValue(); // 输出: Value: 10
    obj2.printValue(); // 输出: Value: 10

    return 0;
}

v2.0 深拷贝

#include <iostream>
#include <cstring> // for memcpy

class MyClass {
public:
    int* value;

    MyClass(int val = 0) {
        value = new int(val);
    }

    ~MyClass() {
        delete value;
    }

    MyClass(const MyClass& other) {
        value = new int;
        memcpy(value, other.value, sizeof(int));
    }

    void printValue() const {
        std::cout << "Value: " << *value << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = obj1; // 深拷贝

    obj1.printValue(); // 输出: Value: 10
    obj2.printValue(); // 输出: Value: 10

    return 0;
}

v3.0 拷贝构造函数

#include <iostream>

class MyClass {
public:
    int value;

    MyClass(int val = 0) : value(val) {}

    MyClass(const MyClass& other) : value(other.value) {}

    void printValue() const {
        std::cout << "Value: " << value << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2(obj1); // 使用拷贝构造函数

    obj1.printValue(); // 输出: Value: 10
    obj2.printValue(); // 输出: Value: 10

    return 0;
}

4.0 拷贝赋值运算符

#include <iostream>

class MyClass {
public:
    int value;

    MyClass(int val = 0) : value(val) {}

    MyClass& operator=(const MyClass& other) {
        if (this != &other) {
            value = other.value;
        }
        return *this;
    }

    void printValue() const {
        std::cout << "Value: " << value << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2;
    obj2 = obj1; // 使用拷贝赋值运算符

    obj1.printValue(); // 输出: Value: 10
    obj2.printValue(); // 输出: Value: 10

    return 0;
}

v5.0 自定义的深拷贝函数

#include <iostream>

class MyClass {
public:
    int* value;

    MyClass(int val = 0) {
        value = new int(val);
    }

    ~MyClass() {
        delete value;
    }

    void deepCopyFrom(const MyClass& other) {
        *value = *other.value;
    }

    void printValue() const {
        std::cout << "Value: " << *value << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2;
    obj2.deepCopyFrom(obj1); // 使用自定义的深拷贝函数

    obj1.printValue(); // 输出: Value: 10
    obj2.printValue(); // 输出: Value: 10

    return 0;
}

v6.0 通过指针进行拷贝

#include <iostream>

class MyClass {
public:
    int* value;

    MyClass(int val = 0) {
        value = new int(val);
    }

    MyClass(const MyClass& other) {
        value = new int(*other.value);
    }

    ~MyClass() {
        delete value;
    }

    void printValue() const {
        std::cout << "Value: " << *value << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = obj1; // 通过指针进行拷贝

    obj1.printValue(); // 输出: Value: 10
    obj2.printValue(); // 输出: Value: 10

    return 0;
}

v7.0 移动语义

#include <iostream>

class MyClass {
public:
    int* value;

    MyClass(int val = 0) {
        value = new int(val);
    }

    MyClass(MyClass&& other) : value(other.value) {
        other.value = nullptr;
    }

    ~MyClass() {
        delete value;
    }

    void printValue() const {
        std::cout << "Value: " << *value << std::endl;
    }
};

int main() {
    MyClass obj1(10);
    MyClass obj2 = std::move(obj1); // 移动语义

    obj1.printValue(); // 这里会输出一个未定义的值(因为已移动)
    obj2.printValue(); // 输出: Value: 10

    return 0;
}

v8.0 将对象other的内容复制到当前对象中(即this指针)

```cpp
#include <iostream>
#include <cstring>

class MyClass {
public:
    int value;

    void copyFrom(const MyClass& other) {
        memcpy(this, &other, sizeof(MyClass));
    }
};

int main() {
    MyClass obj1;
    obj1.value = 10;

    MyClass obj2;
    obj2.copyFrom(obj1);

    std::cout << "obj2.value: " << obj2.value << std::endl;

    return 0;
}

1.优点:
使用memcpy函数将&other对象的内存内容复制到this指针所指向的内存中。这样做的目的是实现对象之间的值复制,包括成员变量的值以及可能存在的虚函数表指针等。

2.缺点:
虽然使用memcpy可以将对象的内存内容直接复制到目标对象,但这种方式可能会导致未定义行为。这是因为memcpy是对内存进行字节级别的复制,无法处理对象中的特殊情况,如动态分配的内存、虚函数表指针等。因此,对于自定义的类,更推荐使用逐个复制成员变量的方式来实现对象之间的值复制,以确保复制的正确性和安全性。例如:

void copyFrom(const MyClass& other) {
    this->value = other.value;
    // 在实际的代码中,可能还需要逐个复制其他成员变量
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1029642.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

宝塔重装注意事项

欢迎关注我的公众号&#xff1a;夜说猫&#xff0c;让一个贫穷的程序员不靠打代码也能吃饭~ 前言 宝塔8.0版本&#xff0c;宝塔卸载重装&#xff0c;或者重装Linux系统后重新安装宝塔也适用。 不能上来直接就执行安装宝塔脚本&#xff0c;除非之前没有安装过宝塔。 步骤 1、…

短视频源码php

对于php短视频源码而言&#xff0c;视频质量与用户使用体验息息相关&#xff0c;高质量的视频观感更有利于留下用户。但实际上视频质量很容易受到各种因素的影响&#xff0c;接下来我们分析一下php短视频源码中导致视频出现异常的各种原因吧。 所谓短视频源码的原生开发&#…

华为云云耀云服务器L实例评测|华为云上安装kafka

文章目录 华为云云耀云服务器L实例评测&#xff5c;华为云上安装kafka一、kafka介绍二、华为云主机准备三、kafka安装1. 安装什么版本java2. 安装zookeeper服务3. 使用systemctl 管理启动ZooKeeper服务4. 修改kafka配置5. 使用systemctl 管理启动kafka服务6. 创建一个测试 topi…

Springboot 实践(21)服务熔断机制

在微服务架构中&#xff0c;服务众多&#xff0c;通常会涉及到多个服务层的调用&#xff0c;一旦基础服务发生故障&#xff0c;很可能会导致级联故障&#xff0c;继而造成整个系统不可用&#xff0c;这种现象被称为服务雪崩效应。 服务熔断引入熔断器概念&#xff0c;熔断器如果…

libopenssl 实现私钥加密公钥解密

在需要验证可信来源时&#xff0c;需要用到签名验签。因此&#xff0c;需要使用私钥加密&#xff0c;公钥解密&#xff0c;取得被加密的信息。这就会使用到私钥加密&#xff0c;公钥解密的场景了。 参考&#xff1a; https://github.com/openssl/openssl/issues/20493 https:/…

【Python】Pycharm使用anaconda中的PaddleOCR的虚拟环境 卡在loading package list(保姆级图文)

目录 异常表现&#xff1a;解决方法1. 试着使用pytcharm的http代理&#xff08;很确定没用&#xff0c;无法成功&#xff0c;直接看下一步&#xff09;2. conda换国内源&#xff08;换源后重启&#xff1f;不知道有没有用&#xff0c;不确定是否关键&#xff09;3. 在conda中更…

2023年浙工商MBA新生奖学金名单公布,如何看待?

浙工商MBA项目官方最新公布了2023年的非全日制新生奖学金名单&#xff0c;按照政策约定&#xff0c;共分为特等奖学金1名&#xff0c;一等奖学金10名&#xff0c;二等奖学金15名&#xff0c;三等奖学金30名&#xff0c;额度对应3万、1万、0.8万、0.5万不等&#xff0c;主要名单…

c++ 继承与多态

一、c如何解决菱形继承的问题 例子一 菱形继承问题 #include <iostream> #include <string.h> using namespace std; class Animal { public:int m_Age; }; class Sheep : public Animal {}; class Tuo : public Animal {}; class SheepTuo :public Sheep, publ…

phpstudy脚本编写 和sql注入编写

1.phpstudy编写 2.sql注入编写

一、iMove源码解读:初识

引言&#xff1a;随着低代码思想的不断蔓延&#xff0c;除了大企业&#xff0c;中小企业也尝试构建自己的低代码平台&#xff0c;以期降低开发门槛&#xff0c;提高开发效率&#xff0c;降低生产成本。本文中的iMove是一款面向前端开发者的逻辑编排工具&#xff0c;通过它设计出…

【Java 基础篇】Java线程安全与并发问题详解

多线程编程在Java中是一个常见的需求&#xff0c;它可以提高程序的性能和响应能力。然而&#xff0c;多线程编程也带来了一系列的线程安全与并发问题。在本文中&#xff0c;我们将深入探讨这些问题&#xff0c;以及如何解决它们&#xff0c;适用于Java初学者和基础用户。 什么…

机器学习入门教学——损失函数(交叉熵法)

1、前言 我们在训练神经网络时&#xff0c;最常用到的方法就是梯度下降法。在了解梯度下降法前&#xff0c;我们需要了解什么是损失(代价)函数。所谓求的梯度&#xff0c;就是损失函数的梯度。如果不知道什么是梯度下降的&#xff0c;可以看一下这篇文章&#xff1a;机器学习入…

人工智能的未来:技术与道德的交汇

人工智能的未来&#xff1a;技术与道德的交汇 摘要引言技术的前景1. 机器学习的进展2. 自主智能系统 道德考量3. 数据隐私与安全4. 自主决策的伦理 社会影响5. 就业与教育6. 医疗与健康 总结参考资料 博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客&#x1f466;…

新款 锐科达 SV-2402VP SIP广播音频模块 支持RTP流音频广播

新款 锐科达 SV-2402VP SIP广播音频模块 支持RTP流音频广播 SV-2402VP网络音频模块是一款通用的独立SIP音频功能模块&#xff0c;可以轻松地嵌入到OEM产品中。该模块对来自网络的SIP协议及RTP音频流进行编解码。 该模块支持多种网络协议和音频编解码协议&#xff0c;可用于VoI…

Spring底层原理之 BeanFactory 与 ApplicationContext

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Spring底层原理 一、 BeanFactory 与 Appli…

华为杯数学建模比赛经验分享第二期——编程手篇

数学建模比赛中编程手是较为重要的角色&#xff0c;不仅需要根据建模手的思路完成代码的编写&#xff0c;还需要与写作手沟通结果分析与呈现。 所以&#xff0c;编程手必须在不同的阶段完成相应的学习&#xff0c;这里我把它分为赛前和赛中。 1、赛前 在短短4天的学习新的代码…

虚拟DOM与diff算法

虚拟DOM与diff算法 snabbdom虚拟DOMdiff算法 snabbdom 是什么&#xff1a;snabbdom是著名的虚拟DOM库&#xff0c;是diff算法的鼻祖&#xff0c;Vue源码借鉴了snabbdom 虚拟DOM 是什么&#xff1a;本质上是存在内存里的 JavaScript 对象 作用&#xff1a;用来描述真实DOM的层…

DA2--获取网站用户数据集的大小

目录 1.题目描述 2.输入描述 3.输出描述 4.题目分析 5.通过代码 1.题目描述 现有一个Nowcoder.csv文件&#xff0c;它记录了牛客网的部分用户数据&#xff0c;包含如下字段&#xff08;字段与字段之间以逗号间隔&#xff09;&#xff1a; Nowcoder_ID&#xff1a;用户ID…

Vue 使用vue-cli构建SPA项目(超详细)

目录 一、什么是vue-cli 二&#xff0c;构建SPA项目 三、 运行SPA项目 前言&#xff1a; 在我们搭建SPA项目时候&#xff0c;我们必须去检查我们是否搭建好NodeJS环境 cmd窗口输入以下指令&#xff1a;去检查 node -v npm -v 一、什么是vue-cli Vue CLI&#xff08;Vu…

【智能电表数据接入物联网平台实践】

智能电表数据接入物联网平台实践 设备接线准备设备调试代码实现Modbus TCP Client 读取电表数据读取寄存器数据转成32bit Float格式然后使用modbusTCP Client 读取数据 使用mqtt协议接入物联网平台最终代码实现 设备接线准备 设备调试 代码实现 Modbus TCP Client 读取电表数…