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

C++:拷贝构造函数

一、什么是拷贝构造函数?

拷贝构造函数是一种特殊的构造函数,它的参数是同类型对象的常量引用,即用已存在的一个变量初始化另一个同类型变量。

classPerson{public:// 拷贝构造函数Person(constPerson&other){name=other.name;age=other.age;cout<<"拷贝构造被调用"<<endl;}// 其他...private:string name;intage;};

二、拷贝构造函数的语法规则

  • 函数名与类名相同。

  • 没有返回值。

  • 参数必须是同类型对象的引用,通常为 const 。

  • 可以自定义,也可以让编译器自动生成。

classMyClass{public:// 拷贝构造函数的典型形式MyClass(constMyClass&other);};
为什么参数要写引用
  • 如果类没有管理动态资源(比如没有 new 分配内存),我们其实只需要把原对象的值复制给新对象就够了。那能不能直接把原对象的值当作普通参数传给拷贝构造函数,让它用这个值来初始化新对象呢?
  • 答案是不行,原因在于:
    • C++规定:传值传参必须调用拷贝构造。而我们若在实现拷贝构造时使用传值传参,则又会生成新的拷贝构造,如此不断生成新的拷贝构造,最后会造成死循环。

三、何时调用拷贝构造函数?

用一个对象初始化另一个对象
Personp1("Alice",25);Person p2=p1;// 调用拷贝构造Personp3(p1);// 调用拷贝构造
函数参数按值传递
voidfunc(Person p){...}func(p1);// 实参p1拷贝给形参p,调用拷贝构造
函数按值返回对象
Personcreate(){Persontemp("Bob",30);returntemp;// 返回值时可能调用拷贝构造(或移动语义)}
容器中的元素插入

当容器需要复制元素时,会调用拷贝构造。(如 vector 的 push_back)

四、默认拷贝构造函数

编译器自动生成的拷贝构造
  • 如果类中没有定义拷贝构造函数,编译器会自动生成一个,它执行浅拷贝(shallow copy):逐个复制成员变量的值。
什么时候需要自己写拷贝构造?
  • 当类中有指针成员并指向动态分配的内存时,浅拷贝会导致两个对象共享同一块内存(应该为新对象申请一块新的内存,需要自己手动实现,若执行浅拷贝,则会直接),释放时会产生重复释放或内存泄漏。
classShallow{public:int*data;Shallow(intval){data=newint(val);}// 编译器生成的默认拷贝构造:data = other.data(浅拷贝)};intmain(){Shallowa(10);Shallow b=a;// 两个对象的data指向同一块内存!// 析构时会重复释放,导致未定义行为。}

五、深拷贝:自定义拷贝构造函数

  • 为了正确复制包含动态资源的对象,我们需要自定义拷贝构造函数,执行深拷贝(deep copy):申请一块新的空间,再复制原指针指向的内容。
classDeep{int*data;public:Deep(intval){data=newint(val);}// 深拷贝构造Deep(constDeep&other){data=newint(*other.data);// 重新分配并复制值}~Deep(){deletedata;}};intmain(){Deepa(10);Deep b=a;// 深拷贝,各自拥有独立内存// 安全销毁}

六、拷贝构造与赋值运算符的区别

  • 拷贝构造:用已有对象初始化新对象(对象尚未创建)。
  • 赋值运算符:将已有对象的值赋给已存在的对象(对象已创建)。
Personp1("Alice",25);Person p2=p1;// 拷贝构造(p2尚未创建)Personp3("Bob",30);p3=p1;// 赋值运算符(p3已存在)

七、禁止拷贝

  • 如果类不希望被复制,可以显式删除拷贝构造函数(C++11):
classNonCopyable{public:NonCopyable()=default;NonCopyable(constNonCopyable&)=delete;// 禁止拷贝};

八、如何使用

  • 如果有资源的申请分配,一般要自己实现。

  • 如果自定义了析构函数、拷贝构造、拷贝赋值其中之一,通常需要自定义其他每个。

  • 优先使用深拷贝:当类管理动态内存时,务必实现深拷贝。

  • 用 const 引用:避免不必要的拷贝,提高性能。

  • 使用移动语义(C++11)减少拷贝开销,适合临时对象。

九、完整示例

#include<iostream>#include<cstring>usingnamespacestd;classString{char*buf;public:String(constchar*s=""){buf=newchar[strlen(s)+1];strcpy(buf,s);}// 拷贝构造(深拷贝)String(constString&other){buf=newchar[strlen(other.buf)+1];strcpy(buf,other.buf);cout<<"拷贝构造"<<endl;}~String(){delete[]buf;}voidshow()const{cout<<buf<<endl;}};intmain(){Strings1("Hello");String s2=s1;// 调用拷贝构造s1.show();s2.show();return0;}

十、总结

  • 拷贝构造函数控制对象如何被复制,是类设计的重要一环。

  • 浅拷贝适合简单类,管理资源的类需要深拷贝。

  • 编译器默认生成拷贝构造,但自定义更灵活、更安全。

http://www.cnnetsun.cn/news/3126471.html

相关文章:

  • 椭圆曲线 Diffie-Hellman 密钥交换解题思路
  • 集团知识管理平台建设方案:74页PpT爆款干货全解析!
  • 【2026万字实录】从理论到实战:网络信息安全全景深度解析与避坑指南
  • 后 Django 时代:SQLAlchemy 2.0、Tortoise 与 Piccolo 三大异步 ORM 选型指南
  • 几分钟完成 OpenClaw 安装,Windows 可视化步骤新手直接照搬
  • 手撕字符串算法:反转、回文、验证回文 Ⅱ 完整拆解
  • 带标注的骑电动车是否佩戴头盔数据集,识别率77.1%,1345张图,支持yolo,coco json,voc xml,文末有模型训练代码
  • 3个核心功能解决你的Windows日志分析困境:为什么LogExpert能成为开发运维的终极利器?
  • DellFanManagement:戴尔笔记本终极风扇控制解决方案,告别噪音与过热烦恼!
  • 预约留资小程序制作工具测评:餐宝盈/BBWEYY/比文云/Landingi/Webnode(2026年7月更新)含零代码SAAS、AI编程、源码定制交付
  • GPT-4o与文心一言4.5:当前主流大模型真实进展解析
  • 芯原推出CPP2000摄像头后处理IP,赋能具身机器人和移动视觉应用
  • 云系列和Terraform(十二)
  • WidescreenFixesPack:让70+款经典游戏在现代宽屏显示器上完美运行的终极方案
  • Claude为什么这么聪明?揭秘藏在每个AI大模型背后的“注意力魔法“
  • 02-SpringBoot配置文件
  • 华为MetaERP OM 一致性对账 SQL 脚本集合(OM-WSH、WSH-INV、OM-AR、异常订单筛查)
  • 无感FOC与滑膜观测器在电机控制中的应用
  • 建筑外立面缺陷智能识别:YOLOv26驱动下的多类损伤检测数据集与实战10748期
  • 1kW高效BLDC电机设计:医疗设备应用与转矩脉动控制
  • 保姆级外部字幕添加教程 3步搞定播放器字幕加载
  • aixingpan.cn API开发文档:api_docs_onechart_lunar_return2接口指南
  • 大模型应用中的“中转层”到底解决了什么问题?
  • [对比评测]SendTomo和LocalSend哪个更适合文件传输
  • Linux服务器Jmeter压测实战:环境搭建、脚本优化与性能分析
  • RAG检索增强策略:混合检索、重排序与Query改写
  • 量子阱结构二极管:电子元器件的颠覆性创新
  • SQL慢_分析 执行计划突变
  • 一键生成公众号文章自动排版工具实战指南
  • 达梦数据库SSL/TLS加密实战:从证书生成到客户端配置全解析