【C++】类和对象(5)--拷贝构造函数

目录

一 概念

二 拷贝构造函数特性

1. 重载形式

2. 参数原则

3 默认拷贝函数

三 拷贝构造函数的实现


一 概念

在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?

class Date
{
public:
       Date(int year = 1900, int month = 1, int day = 1)//默认构造函数
       {
              _year = year;
              _month = month;
              _day = day;
       }

       
       void Print()
       {
              cout << _year << "/" << _month << "/" << _day << endl;
       }

private:
       int _year;
       int _month;
       int _day;
};


class Stack
{
public:
       Stack(size_t capacity = 3)
       {
              cout << "Stack(size_t capacity = 3)" << endl;

              _a = (int*)malloc(sizeof(int) * capacity);
              if (nullptr == _a)
              {
                      perror("malloc申请空间失败!!!");
              }

              _capacity = capacity;
              _top = 0;
       }

       ~Stack()
       {
              cout << "~Stack()" << endl;

              free(_a);
              _capacity = _top = 0;
              _a = nullptr;
       }

private:
       int* _a;
       int _capacity;
       int _top;
};


//值拷贝浅拷贝
void func1(Date d)//形参是实参拷贝
{
       d.Print();
}

void func2(Stack st)//这样拷贝这是不行的
{
       //...
}

int main()
{
       Date d1(2023, 10, 22);
       func1(d1);

       Stack st1;
       func2(st1);

       return 0;
}

 我们可以看到Date类就能传参 但是Stack类就不行, 这涉及到了浅拷贝, 深拷贝

如何解决?

规定, 自定义类型对象拷贝的时候, 调用一个函数, 这个函数就叫拷贝构造

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存 在的类类型对象创建新对象时由编译器自动调用

拷贝构造函数通常用于:

• 通过使用另一个同类型的对象来初始化新创建的对象。

• 复制对象把它作为参数传递给函数。

• 复制对象,并从函数返回这个对象。
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)//默认构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year;
	int _month;
	int _day;
};


void func1(Date d)//调用拷贝构造 -->形参是实参的拷贝
{
	/*
	(1).d1对象传入形参时,会先会产生一个临时变量,就叫 d。
	(2).然后调用拷贝构造函数把d1的值给d。 整个这两个步骤有点像:Date d(d1);
	(3).等func1()执行完后, 析构掉 d 对象。
	*/
}

Date func2()
{
	Date d2(2023, 11, 20);
	return d2;//调用拷贝构造
	/*
	(1).先会产生一个临时变量,就叫XXXX吧。
	(2).然后调用拷贝构造函数把d2的值给XXXX。整个这两个步骤有点像:Date XXXX(d2);
	(3).在函数执行到最后先析构d2局部变量。
	(4).等func2()执行完后再析构掉XXXX对象。
	*/
}

int main()
{
	Date d1(2023, 10, 22);
	func1(d1);
	Date d3(d1); //调用拷贝构造
	Date d4 = d1;//调用拷贝构造
	return 0;
}

二 拷贝构造函数特性

拷贝构造函数也是特殊的成员函数,其特征如下:

1. 重载形式

拷贝构造函数是构造函数的一个重载形式。

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    // Date(const Date d)--> 错误写法:编译报错,会引发无穷递归
    Date(const Date& d) 
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d1;
    Date d2(d1);//将d1拷贝给d2
    return 0;
}

2. 参数原则

拷贝构造函数的参数只有一个且必须是类类型对象的引用

使用传值方式编译器直接报错, 因为会引发无穷递归调用。

 

3 默认拷贝函数

若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按 字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝

前面已经说了Date类就用编译器生成的默认拷贝构造函数就可以了 不用显示定义构造函数了

注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请 时,则拷贝构造函数是一定要写的,需要深度拷贝,否则就是浅拷贝

三 拷贝构造函数的实现

像栈 这些涉及到了资源的申请, 那就需要深度拷贝了

class Stack
{
public:
       Stack(size_t capacity = 3)
       {
              cout << "Stack(size_t capacity = 3)" << endl;

              _a = (int*)malloc(sizeof(int) * capacity);
              if (nullptr == _a)
              {
                      perror("malloc申请空间失败!!!");
              }

              _capacity = capacity;
              _top = 0;
       }

       // Stack st2(st1);
       Stack(const Stack& stt)
       {
              cout << " Stack(Stack& stt)" << endl;
              // 深拷贝
              _a = (int*)malloc(sizeof(int) * stt._capacity);
              if (_a == nullptr)
              {
                      perror("malloc fail");
                      exit(-1);
              }
              memcpy(_a, stt._a, sizeof(int) * stt._top);
              _top = stt._top;
              _capacity = stt._capacity;
       }

       ~Stack()
       {
              cout << "~Stack()" << endl;

              free(_a);
              _capacity = _top = 0;
              _a = nullptr;
       }

private:
       int* _a;
       int _capacity;
       int _top;
};

class MyQueue
{
       Stack _pushst;
       Stack _popst;
       int _size = 0;
};


void func2(Stack st)
{
       //...
}

int main()
{
       Stack st1;
       func2(st1);
       Stack st2(st1);

       MyQueue q1;
       MyQueue q2(q1);

       return 0;
}

总结:

Date 和 MyQueue 默认生成拷贝就可以用        

1、内置类型成员完成值拷贝        

2、自定义类型成员调用这个成员的拷贝构造        

Stack需要自己写拷贝构造,完成深拷贝   顺序表、链表、二叉树等等的类,都需要深拷贝 

本节难度比较简单, 但是对基础性要求较强, 对构造函数还有不太懂的朋友可以去我的博客:

【C++】类和对象(2)--构造函数-CSDN博客

继续加油!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vscode的git 工具使用

vscode的git 工具使用 目录概述需求&#xff1a; 设计思路实现思路分析1.git 工具的使用2.提交代码3.查看历史提交代码 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a be…

关于接口测试自动化的总结与思考!

序 近期看到阿里云性能测试 PTS 接口测试开启免费公测&#xff0c;本着以和大家交流如何实现高效的接口测试为出发点&#xff0c;本文包含了我在接口测试领域的一些方法和心得&#xff0c;希望大家一起讨论和分享&#xff0c;内容包括但不仅限于&#xff1a; 服务端接口测试介…

FPGA实现Avalon-MM接口通信

在Avalon总线协议&#xff08;一&#xff09;和Avalon总线协议&#xff08;二&#xff09;中大概了解Avalon总线的几种类型&#xff0c;目前比较常用到的就是Avalon-MM接口了&#xff0c;虽然在概念中有那么多的属性&#xff0c;但是具体使用起来还是非常简单的。 一、Avalon-…

【Mysql】关于数据库增删查改的一些在线OJ练习

&#x1f308;欢迎来到Python专栏 &#x1f64b;&#x1f3fe;‍♀️作者介绍&#xff1a;前PLA队员 目前是一名普通本科大三的软件工程专业学生 &#x1f30f;IP坐标&#xff1a;湖北武汉 &#x1f349; 目前技术栈&#xff1a;C/C、Linux系统编程、计算机网络、数据结构、Mys…

大数据-之LibrA数据库系统告警处理(ALM-12048 网络写包错误率超过阈值)

告警解释 系统每30秒周期性检测网络写包错误率&#xff0c;并把实际错误率和阈值&#xff08;系统默认阈值0.5%&#xff09;进行比较&#xff0c;当检测到网络写包错误率连续多次&#xff08;默认值为5&#xff09;超过阈值时产生该告警。 用户可通过“系统设置 > 阈值配置…

PLC和SCADA有什么区别?

让我们谈谈SCADA和HMI之间的区别。今天&#xff0c;我们将讨论它们的区别和相似之处&#xff0c;以及各自的用途。由于相似之处&#xff0c;通常会出现一些混淆。 现在让我们深入了解SCADA 。SCADA代表“监控和数据采集”。它们用于监视和控制大面积区域&#xff0c;通常是整个…

Vue3 使用教程

目录 一、创建vue3工程1. 使用vue-cli创建2.使用 vite 创建 二、setup使用三、ref函数四、reactive函数五、计算属性与监视属性5.1 computed函数5.2 watch函数5.3 watchEffect函数 六、自定义hook函数七、toRef函数八、shallowReactive 与 shallowRef九、readonly 与 shallowRe…

Vue23全局事件总线

Vue2&3全局事件总线 Vue2全局事件总线 功能&#xff1a;可以解决所有组件之间通信传数据的问题原理&#xff1a;通过一个共享对象&#xff0c;将所有组件全部绑定到对象上&#xff0c;即可通过这个对象实现组件与组件之间的传递数据&#xff0c;而这个共享对象叫做全局事件…

TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…

【JUC】八、阻塞队列

文章目录 1、阻塞队列概述2、阻塞队列分类3、 阻塞队列的四组核心方法4、Demo 队列&#xff0c;先进先出&#xff0c;类似排队栈&#xff0c;先进后出&#xff0c;用于要优先处理最近发生的事件的场景 1、阻塞队列概述 阻塞队列&#xff0c;一个生产消费模式&#xff0c;当&a…

数组相关面试题--5.合并两个有序数组

5. 合并两个有序数组 88. 合并两个有序数组 - 力扣&#xff08;LeetCode&#xff09; 解题思路:1. 从后往前遍历数组&#xff0c;将nums1和nums2中的元素逐个比较将较大的元素往nums1末尾进行搬移2. 第一步结束后&#xff0c;nums2中可能会有数据没有搬移完&#xff0c;将nums…

结合scss实现黑白主题切换

是看了袁老师的视频后&#xff0c;自己做了一下练习。原视频地址&#xff1a; b站地址https://www.bilibili.com/video/BV15z4y1N7jB/?spm_id_from333.1007.top_right_bar_window_history.content.click&vd_sourcec6cf63302f28d94ebc02cbedcecc57ea首先创建一个全局的scs…

Python的基础:模块(Modules)和包(Packages)详解

1. 模块&#xff08;Modules&#xff09; 一个模块是一个包含了 Python 定义和语句的文件。模块可以包括变量、函数、类等&#xff0c;并且提供了一种将相关代码组织成可重用单元的方式。一个模块的定义通常包括以下几个方面&#xff1a;   1&#xff09;文件扩展名&#xff…

17. Series.dt.month-提取日期数据中的月份信息

【目录】 文章目录 17. Series.dt.month-提取日期数据中的月份信息1. 知识回顾-创建一个Series对象2. 知识回顾-pd.to_datetime()将数据转换为pandas中的日期时间格式3. 实例化类相关知识4. Series.dt.month是什么&#xff1f;5. 如何使用Series.dt.month&#xff1f;6. Series…

【数据库原理及应用教程】第三章 SQL

文章目录 建立数据库创建数据库选择元组select多表查询 追加元组 insert嵌套子查询 元组删除命令 deleteUpdate命令 修正与撤销数据库SQL-DDL撤销与修改撤销基本表指定数据库关闭数据库 建立数据库 学生选课数据库SCT 学生表&#xff1a;Student(SNo char(8), Sname char(10)…

Ubuntu18.04安装Loam保姆级教程

系统环境&#xff1a;Ubuntu18.04.6 LTS 1.Loam的安装前要求&#xff1a; 1.1 ROS安装&#xff1a;参考我的另一篇博客 Ubuntu18.04安装ROS-melodic保姆级教程_灬杨三岁灬的博客-CSDN博客还是那句话&#xff0c;有时候加了这行也不好使&#xff0c;我是疯狂试了20次&#xf…

stylelint报错at-rule-no-unknown

stylelint报错at-rule-no-unknown stylelint还将各种 sass -rules 标记mixin为include显示未知错误 at-rule-no-unknown ✖ stylelint --fix:Deprecation warnings: 78:1 ✖ Unexpected unknown at-rule "mixin" at-rule-no-unknown 112:3 ✖ Unexpected un…

2023 年 数维杯(A题)国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2021年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 让我们来看看数维杯A题&#xff01; 问题重述 1、俯仰力矩和俯…

【Rust】快速教程——冻结表达式

前言 以前谁是魔我杀谁&#xff0c;现在我杀谁谁就是魔。——《拔魔》 \;\\\;\\\; 目录 前言Rust基本知识结构体元组结构体局部作用域冻结字面量Vec元素的类型由第一个push进的类型确定type别名from和intoTryFrom和TryInto 表达式 Rust基本知识 结构体 #[derive(Debug)] str…

华为eNSP综合实验考试

VLAN信息表 设备名称 端口 链路类型 VLAN 参数 HZ-HZCampus-Agg01-S5731 GE0/0/1 Trunk PVID:1 Allow-pass&#xff1a;10 20 Eth-trunk1&#xff08;GE0/0/2,0/0/3,0/0/23&#xff09; Trunk PVID:1 Allow-pass&#xff1a;10 20 GE0/0/24 Access PVID&#xf…