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

C++:从拷贝构造函数到深浅拷贝

拷贝构造函数

当实例化一个新对象并使用同类型对其进行初始化时,会显式调用类的拷贝构造函数,拷贝构造函数写法:形参为const修饰的同类型类引用。拷贝构造函数有个需要注意的点,形参为何是只允许传递引用呢?原因在于若传递的是值,那么在调用拷贝构造函数时形参拷贝到实参时会再次发生拷贝,就会无休止的调用拷贝构造函数。

A(const A& a) { cout << "拷贝构造函数" << endl; }

赋值运算符重载

赋值运算符重载与拷贝构造函数有些相似,同样也是用同类型的对象初始化本对象。区别在于若对象已经存在,无需重新实例化时,赋值运算符操作则会调用重载函数。赋值运算符重载函数一般写成返回值为类的引用,形参为const修饰的类引用。

A& operator=(const A& a) {
	cout << "重载赋值运算符" << endl;
	return *this;
}

若没有手动实现这两个函数,在发生拷贝构造或赋值运算时,程序会调用按照位拷贝的方式生成默认函数并调用。位拷贝的方式为“浅拷贝”。若类中没有申请的内存,这种拷贝方式是安全的,但是若类中成员变量存在申请的内存char* buf = new char[1024],那么这种拷贝方式会造成指针垂挂,可能会出现二次析构等不安全的情况。这种时候就需要手动使用深拷贝的方式实现赋值函数与拷贝构造函数。

浅拷贝

浅拷贝的意思是使用指针指向同一个内存空间,类似于C++中的引用。

A* a = new A;
A* b = nullptr;
b = a;

这种方式的效果是两个指针的解引用值是一样的,不管修改哪一个,另外一个输出出来都是一样的,因为他们根本指向的是同一块地址

// 赋值操作
int main()
{
    int* i = new int(1);
    int* j;
    j = i;
    *i = 5;
    cout << *i << " - " << *j << endl;
    delete i;
}
// 拷贝构造
int main()
{
    int* i = new int(1);
    int* j = i;
    *i = 5;
    cout << *i << " - " << *j << endl;
    delete j;
}

/*****************************************
* 结果为 5 - 5
* /

深拷贝

深拷贝的意思是重新申请一份内存,然后将原内存的数据存入到新内存中,这样两份副本是完全独立的,互不影响的

int main()
{
    int* i = new int(1);
    int* j = new int(*i);
    *i = 5;
    cout << *i << " - " << *j << endl;
    delete i;
    delete j;
}

总结

那么在类中若是存在指针的情况下,尽可能都手动实现赋值函数和拷贝构造函数,并使用深拷贝的方式去实现

class A {
public:
    A(int i) { Pi = new int(i); }
    ~A() { if (Pi) delete Pi; }

    A(const A& a) {
        if (Pi)
            delete Pi;
        Pi = new int(*a.Pi);
    }

    A& operator=(const A& a) {
        if (this != &a)
        {
            if (Pi)
                delete Pi;
            Pi = new int(*a.Pi);
        }
        return *this;
    }

    int* Pi = nullptr;
};

int main()
{

    A a(0);
    A b = a;
    A c(0);
    c = a;
    *a.Pi = 5;
    cout << *a.Pi << " - " << *b.Pi << " - " << *c.Pi << endl;
}

/* 输出为: 5 - 0 - 0 */

文章转载自:

http://XKVHHc9b.mmzfL.cn
http://vMjloHjx.mmzfL.cn
http://YfSm9aJp.mmzfL.cn
http://dRFghX6P.mmzfL.cn
http://Mm4xa7rV.mmzfL.cn
http://wkwljGaB.mmzfL.cn
http://OwGp2Bzf.mmzfL.cn
http://ChtA679F.mmzfL.cn
http://z9l9J0Bu.mmzfL.cn
http://jqZc3E9R.mmzfL.cn
http://YDzcedLL.mmzfL.cn
http://TwyP13fu.mmzfL.cn
http://qsak7H7F.mmzfL.cn
http://jEpAnUcf.mmzfL.cn
http://B58Ou1bM.mmzfL.cn
http://9mjSX7qW.mmzfL.cn
http://Yc43VG0r.mmzfL.cn
http://JxKndgGD.mmzfL.cn
http://4SPdqBU3.mmzfL.cn
http://VFu1mL81.mmzfL.cn
http://4H9RiFQH.mmzfL.cn
http://0getxqas.mmzfL.cn
http://8i9pwe3Q.mmzfL.cn
http://jK1mgJSO.mmzfL.cn
http://fGoTMlqW.mmzfL.cn
http://Z8QMuIPy.mmzfL.cn
http://1fzNrp67.mmzfL.cn
http://18u9JiHW.mmzfL.cn
http://5fTxPLRu.mmzfL.cn
http://0Vni8UPT.mmzfL.cn
http://www.dtcms.com/a/28589.html

相关文章:

  • 如何修改Windows系统Ollama模型存储位置
  • 第三章 组件(7)- 布局与Sections
  • Java——面向对象编程
  • 使用多态来替换条件语句
  • 【嵌入式Linux应用开发基础】进程间通信(3):共享内存
  • 遗传算法与深度学习实战系列,自动调优深度神经网络和机器学习的超参数
  • 完美转发使用
  • 现代任务调度系统架构深度解析——以TaskSchedulerController为核心的弹性任务管理方案
  • Spring AI集成Ollama调用本地大模型DeepSeek
  • Spring AOP
  • langflow中添加Siliconflow组件
  • 拆解微软CEO纳德拉战略蓝图:AI、量子计算、游戏革命如何改写未来规则!
  • DAY01-如何合理配置线程池的核心参数
  • 【机器学习】衡量线性回归算法最好的指标:R Squared
  • js中常用方法整理
  • 动态库和静态库(Linux环境)
  • TOGAF之架构标准规范-信息系统架构 | 应用架构
  • Leetcode2595:奇偶位数
  • 纯手工搭建整套CI/CD流水线指南
  • 基于深度学习进行呼吸音检测的详细示例
  • 物联网简介集合
  • 数电笔记——第一章 数制和码制
  • 基于 Flask 与 MySQL 构建简单的博客系统
  • Java并发编程——并发容器
  • 【Research Proposal】基于提示词方法的智能体工具调用研究——研究现状
  • 动态库加载(可执行程序和地址空间)
  • 用LightRAG+智谱GLM-4提升政务对话精度:从知识图谱到精准问答的实战指南
  • 25重庆事业单位联考明日报名[特殊字符]全流程[特殊字符]
  • Dev-Atlas:典型发育青少年功能性脑网络参考图谱
  • RedissonClient:ZSet(有序集合)上手教程