c++面向对象第4天---拷贝构造函数与深复制

article/2025/7/27 20:14:28
  • 含有对象成员的构造函数
  • 深复制与浅复制
  • 拷贝(复制)构造函数

第一部分:含有对象成员的构造函数

以下是一个学生 类包含日期成员出生日期的代码

#include<iostream>
using namespace std;
class Date
{
public:Date(int year,int month,int day):year(year),month(month),day(day){cout << "Date 构造函数被调用" << endl;}
void printDate()
{cout << year << "年" << month << "月" << day << "日";
}private:
int year,month,day;};class Student
{
public:Student(string name,Date birthday) : name(name),birthday(birthday){cout << "student 的构造函数被调用" << endl;}Student(string name,int year,int month,int day):name(name),birthday(year,month,day){cout << "Student 的构造函数被调用222" << endl;}void printStudentInfo(){cout << "姓名" << name << ",出生日期" << endl;birthday.printDate();cout << endl;}
private:string name;Date birthday;
};int main()
{Student stu1("小明",{2002,5,4}),stu2("小红",2003,3,6);stu1.printStudentInfo();stu2.printStudentInfo();return 0;
}

Date 构造函数被调用
student 的构造函数被调用
Date 构造函数被调用
Student 的构造函数被调用222
姓名小明,出生日期
2002年5月4日
姓名小红,出生日期
2003年3月6日

小结:含有对象成员的类创建对象时,对象成员的初始化要在初始化列表中,运行时会先调用对象成员的构造函数,再调用当前类自己的构造函数。

第2部分:深复制与浅复制

#include<iostream>
using namespace std;class Mystring
{
public:
Mystring(const char* str)
{length = strlen(str);data = new char[length + 1];strcpy(data,str);
}
~Mystring()
{delete[] data;
}
void printString()
{cout << data << endl;
}private:
char* data;
int length;
};int main()
{Mystring s("Hello world!");s.printString();Mystring s2 = s;s2.printString();return 0;
}

浅复制:浅复制是默认的构造函数

Mystring s2 = s;

没有写拷贝构造函数时,系统会自动生成一个“默认拷贝构造函数”,它会对每个成员变量做“逐成员复制”。

对于普通变量(如 int length)是没问题的,但对于指针(char* data),浅复制只是把地址复制过去,不会新建一份数据内容

 结果就是 s.data 和 s2.data 都指向同一块内存!

这就会导致:

  • 两个对象共享同一块堆内存

  • 当 s 和 s2 析构时,都执行 delete[] data,会对同一内存释放两次,造成程序崩溃或未定义行为(⚠️ 危险)

那么深复制的时候:就是复制内容,而不是复制指针地址,所以你只需要手动实现拷贝构造函数

Mystring(const Mystring& other)
{
    length = other.length;
    data = new char[length + 1];       // 分配新内存
    strcpy(data, other.data);          // 复制内容
}

 

所以这个就是以下的区别:

 

第三部分:拷贝(复制)构造函数

#include<iostream>
using namespace std;class Mystring
{
public:
Mystring(const char* str)
{length = strlen(str);data = new char[length+1];strcpy(data,str);cout << "Mystring的构造函数被调用" << endl;
}
Mystring(const Mystring& str)
{length = str.length;data = new char[length+1];strcpy(data,str.data);cout << "Mystring 的拷贝构造函数被调用" << endl;
}
~Mystring()
{delete[] data;
}
void printString()
{cout << data << endl;
}
private:
char* data;
int length;
};int main()
{Mystring s("Hello world");s.printString();Mystring s2(s);s2.printString();return 0;
}
  • 必须使用引用参数(避免无限递归调用)
  • 通常为 const 引用(保证源对象不被修改)
  • 编译器默认生成(仅当类无用户自定义构造函数时)

那这里面的拷贝构造函数是什么?

Mystring(const Mystring& str)
{length = str.length;data = new char[length + 1];      // 分配新空间strcpy(data, str.data);           // 拷贝字符串内容cout << "Mystring 的拷贝构造函数被调用" << endl;
}

 

用一个已经存在的对象去创建一个新的对象,并且为其分配新的内存( 深拷贝),防止多个对象共享同一块内存。

 Mystring s2(s);

调用拷贝构造函数 Mystring(const Mystring& str) 创建新对象 s2

#include<iostream>
#include<string>
using namespace std;class CPU{
public:CPU(const string& cpu) : model(cpu){cout << "cpu constructed" << endl;}void printInfo() const{cout << "CPU型号" << model << endl;}
private:string model;
};class Monitor{
public:Monitor(const string& monitor) : brand(monitor){cout << "Monitor constructed" << endl;}void printInfo() const{cout << "Monitor品牌" << brand << endl;}
private:string brand;
};class Computer{
public:Computer(int memory,const string& cpuModel,const string& monitorBrand): memory(memory),cpu(cpuModel),monitor(monitorBrand){cout << "Computer构造函数被调用" << endl;}void printInfo() const{cout << "内存容量 " << memory << " GB" << endl;cpu.printInfo();monitor.printInfo();}
private:int memory;CPU cpu;Monitor monitor;
};int main()
{Computer c(16,"Intel 890000","mac");c.printInfo();return 0;
}

 

  1. 定义一个Person类,包含char*类型的name,int age和Adress类型的address。Address是表示地址的类,包含char* street和int类型的houseNumber。请合理实现这两个类,使其能正常的完成如下的使用:
  2. #include <iostream>
    #include <cstring>
    using namespace std;class Address {
    public:Address(const char* streetName, int houseNum) {street = new char[strlen(streetName) + 1];strcpy(street, streetName);houseNumber = houseNum;cout << "Address构造函数被调用" << endl;}Address(const Address& other) {street = new char[strlen(other.street) + 1];strcpy(street, other.street);houseNumber = other.houseNumber;}~Address() {delete[] street;}void printAddress() const {cout << "地址: " << street << ", 门牌号: " << houseNumber << endl;}private:char* street;int houseNumber;
    };class Person {
    public:Person(const char* n, int a, const Address& addr) : age(a), address(addr) {name = new char[strlen(n) + 1];strcpy(name, n);cout << "Person构造函数被调用" << endl;}Person(const Person& other) : age(other.age), address(other.address) {name = new char[strlen(other.name) + 1];strcpy(name, other.name);}~Person() {delete[] name;}void printInfo() const {cout << "姓名: " << name << ", 年龄: " << age << endl;address.printAddress();}private:char* name;int age;Address address;
    };int main() {Address addr("人民路", 100);Person p("张三", 20, addr);p.printInfo();return 0;
    }


http://www.hkcw.cn/article/SkKGwWDRDM.shtml

相关文章

【STM32F1标准库】理论——定时器/计数器中断

目录 一、定时器/计数器简介 1.通用定时器 2.基本定时器 二、时基单元 三、定时器/计数器结构框图 四、程序运行途中改变分频系数后的时序 1.缓冲器 2.预装器 3.RCC时钟树 五、计时计算方法 一、定时器/计数器简介 定时器可以对输入的时钟进行计数&#xff0c;并在计…

樊振东新球队夺欧冠冠军 萨尔布吕肯再创辉煌

北京时间6月1日晚,欧洲乒联冠军联赛男团决赛中,樊振东新赛季将加盟的萨尔布吕肯以3-1战胜杜塞尔多夫,第三次夺得欧冠冠军。比赛具体比分为:弗朗西斯卡2-3卡尔伯格、莫雷加德3-0邱党、达科约奇克3-2波尔、弗朗西斯卡3-2邱党。此前,德甲联赛萨尔布吕肯乒乓球甲级俱乐部宣布樊…

发明江苏足球联赛的人 一定是个天才 城市荣誉之战

江苏城市足球联赛的创立者堪称天才。江苏是一个由十三个地级市组成的省份,每个城市都有自己的特色和骄傲,彼此之间竞争激烈。此前,江苏省文旅部门制作了一个景点介绍视频,但网友们却开始计算各城市的出现时长,甚至有评论说“宿迁凭什么比扬州多三秒”。然而,在这样一个充…

韩国大选投票将开启 4位前总统发声 政坛局势扑朔迷离

韩国再次迎来大选季,选情充满变数。前总统朴槿惠突然发声,而现任总统尹锡悦则选择沉默。提前投票已经开始,民众排队等待投下自己的一票。最新民调显示,共同民主党的支持率逼近40%,而国民力量党则降至32%。执政党面临困境,主要是因为未能有效解决民生问题,年轻选民对此不…

高档烟酒“人情往来”暗藏权钱交易 违纪破法的开端

端午节临近,各级纪检监察机关针对这一节点部署了一系列纠治“四风”的明察暗访工作,重点查处违规吃喝、违规收送礼品礼金等问题,并对顶风违纪行为进行快速处理。近期,各地通报曝光了一批典型问题,相关人员均受到了严肃处理。从近年来各级纪检监察机关查处的腐败案件来看,…

C++输入与输出技术详解

文章目录 引言一、C标准输入输出流1.1 cin与cout1.2 cerr与clog 二、C风格输入输出函数2.1 scanf与printf2.2 fgets与puts 三、输入输出优化四、总结 引言 在C编程中&#xff0c;输入与输出&#xff08;I/O&#xff09;操作是程序与用户、文件或其他系统组件交互的核心环节。C…

文件管理器+APP:高效管理,便捷浏览

在智能手机的日常使用中&#xff0c;文件管理是一项不可或缺的功能。无论是存储照片、视频、文档&#xff0c;还是管理各种应用程序的数据&#xff0c;一个高效、便捷的文件管理器都能显著提升用户的使用体验。文件管理器APP正是这样一款拥有直观界面和易于使用的文件管理器应用…

http协议与https协议

目录 一、认识URL 二、urlencode和urldecode 三、HTTP协议格式 1.HTTP请求 2.HTTP响应 3.简单获取一个http响应 4.简单使用抓包工具 fiddler 四、简单的http代码 1.小知识点 &#xff08;1&#xff09;recv &#xff08;2&#xff09;首页 2.Http代码书写vision…

深入理解 C++11 中的 std::move —— 移动语义详解(小白友好版)

引言 随着 C11 的引入&#xff0c;语言迎来了一个重要特性——移动语义&#xff0c;极大地提升了程序性能&#xff0c;尤其是涉及资源管理的类&#xff08;如 string、vector 等容器&#xff09;的效率。作为移动语义的核心工具&#xff0c;move 扮演着关键角色。本文将从基础…

振动力学的三类基本问题

振动问题的分类依赖于分类的出发点&#xff0c;本文从系统论的角度来分析振动问题的分类。如图1&#xff0c;一个振动系统&#xff0c;包括三个方面&#xff1a;输入、系统特性&#xff08;或称为系统模型&#xff09;、输出。其中&#xff0c;输入指外界载荷&#xff0c;包括力…

西瓜书第十一章——降维与度量学习

文章目录 降维与度量学习k近邻学习原理头歌实战-numpy实现KNNsklearn实现KNN 降维——多维缩放&#xff08;Multidimensional Scaling, MDS&#xff0c;MDS&#xff09;提出背景与原理重述1.**提出背景**2.**数学建模与原理推导**3.**关键推导步骤** Principal Component Analy…

20250531MATLAB三维绘图

MATLAB三维绘图 三维曲线&#xff1a;plot3功能介绍代码实现过程plot3实现效果 三维曲面空间曲面作图命令&#xff1a;meshmeshgrid语法示例应用meshgrid实操训练 peakspeaks 的基本用法peaks数学表达式实操训练自定义网格大小使用自定义网格 meshMATLAB代码对齐快捷键Ctrli墨西…

郑钦文称打5盘都没问题可惜没有 能量满满晋级八强

6月1日,法网女单16强决战中,中国选手郑钦文经过2小时47分钟的激战,以2-1战胜俄罗斯名将萨姆索诺娃,赢得罗兰-加洛斯的10连胜,首次闯入法网八强。接下来她将对阵萨巴伦卡。首盘比赛中,郑钦文两次被破发后都顽强回破,最终在抢七局中以7-5拿下第一盘。第二盘,郑钦文错失了…

张振朗称《刑侦12》让我过足戏瘾 挑战“人格解离症”角色

由钟澍佳总监制,巢志豪监制,林保怡、陈法蓉、张振朗等领衔主演的TVB刑侦悬疑剧《刑侦12》正在腾讯视频和TVB翡翠台热播。这是张振朗近一年来第三次饰演警员角色。与此前的《反黑英雄》《夺命提示》不同的是,他在《刑侦12》中饰演的刑凯有点“怪”——因为儿时的原生家庭创伤…

魏建军回应邀71岁车手参加拉力赛 精神榜样引热议

在新疆塔克拉玛干N39沙漠落幕的环塔拉力赛现场,长城汽车董事长魏建军回应了邀请71岁车手梁钰祥参赛的原因。此次比赛,长城汽车派出强大阵容,时隔十年再次以多品牌联合形式参赛。梁钰祥驾驶坦克500 Hi4-Z参与T2量产组比赛,在恶劣的沙漠环境和复杂的地形中稳扎稳打,展现了高…

花两千买苹果15被说一眼假 山寨机陷阱需警惕

金华兰溪的杨先生最近经历了一件让人无奈的事。他在直播间花2000元买了一部512G的苹果15 Pro Max,以为捡了大便宜,但到手后发现手机问题不断。从外观、桌面到应用图标,乍一看确实像苹果手机,但点开APP Store时出现的“手机助手”字样立刻暴露了真相,原来这是一部披着苹果外…

柳岩因卡鱼刺进了医院 分享就医经历提醒众人

6月1日,湘籍女星柳岩分享了自己去医院取鱼刺的经历,并提醒大家喉咙卡鱼刺时应尽快就医。她写道:“卡鱼刺是常发生的事,去医院取鱼刺是第一次,无论如何,不要跟鱼刺搏斗,越早去医院,越早解脱,医院技术很好,完全不遭罪。”柳岩出生于湖南省衡阳市,毕业于湖南师范大学,…

一场来自云端的生死自救 当事人讲述更多逃生细节

5月24日,在甘肃省西部的祁连山区域,55岁的滑翔伞爱好者彭玉江在进行地面日常训练时,意外遭遇异常天气状况,被强对流云团卷入后以极快的速度上升至海拔8000多米的高空,这一高度远超普通滑翔伞飞行的安全极限。但他仍坚持住有意识控伞,冲出云层,最后安全着陆。事后,甘肃省…

樊振东留洋是主动走出舒适区 开启乒乓新篇章

2025年6月1日,德国乒乓球甲级联赛(TTBL)的FC萨尔布吕肯俱乐部宣布奥运冠军樊振东正式加盟,将以“欧洲冒险者”的身份征战新赛季。这一消息在国际乒坛引起轰动。与以往中国球员短期留洋不同,樊振东的主动选择不仅体现了个人职业规划的突破,也标志着中国乒乓球运动员国际化…

猎德征婚小伙称微信被加爆 “两栋楼”引热议

5月31日,广州天河猎德村迎来一年一度的龙舟招景盛会,超过150条龙舟齐聚猎德涌,现场热闹非凡。在这场传统活动中,一位小伙的独特征婚方式吸引了所有人的目光。这位姓李的小伙来自广州海珠区仑头,出生于1990年,身高超过1米7,单身已有三年。他身穿龙舟服,胸前挂着写有“两…