C++中类的6个默认成员函数 【拷贝构造函数】

文章目录

    • 拷贝构造函数的使用
      • 拷贝构造对于自定义类型【浅拷贝】
      • 深拷贝
      • 拷贝构造函数典型调用场景

拷贝构造函数的使用

  • 在前几章学习对象的时候,我们有的时候需要一个与已存在对象一某一样的新对象

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

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

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

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用
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(2024,2,1);
	Date d2(d1);
	return 0;
}

在这里插入图片描述

  • 下面我们解释一下:
  • 这里的const可加可不加,但是建议加上
  • 有些人就写这个写昏头了,写反了,不加const的话不会提示

在这里插入图片描述

  • 加上了就知道哪里错了,所以还是加上较好

在这里插入图片描述

  • 这里的拷贝构造必须传引用,要不然会引发无穷递归【反正编译会报错~】

在这里插入图片描述

  • 再看下面代码,我是没有写拷贝构造的,但是这里自动拷贝了,毕竟这个是默认成员函数,这里生成的还和之前几个的默认成员函数还不一样,之前的对默认成员函数对内置类型不处理,而这个拷贝构造对内置类型处理了,如果没有处理,这里就拷贝不出来
  • 说明这里会自动生成一个拷贝构造函数,将值拷贝回去
  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝
class Date
{
public:
	// 构造函数
	Date(int year = 2024, int month = 2, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2024, 2, 1);
	Date d2(d1);
	
	d1.Print();
	d2.Print();

	return 0;
}

在这里插入图片描述

拷贝构造对于自定义类型【浅拷贝】

  • 那么对于自定义类型呢?
class Time
{
public:
	Time(const Time& t)
	{
		_hour = t._hour;
		_minute = t._minute;
		_second = t._second;
		cout << "Time::Time(const Time&)" << endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	Date(int year = 2024, int month = 2, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

	// 自定义类型
	Time _t;
};
int main()
{
	Date d1(2024,2,1);
	Date d2(d1);
	
	d1.Print();
	d2.Print();
	return 0;
}

在这里插入图片描述

  • 我们有一个方法就是强制让编译器生成

  • 加上这一条:

Time() = default;

在这里插入图片描述

深拷贝

  • 刚刚上面的一种场景叫做浅拷贝,还有一个场景就是深拷贝

  • 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

  • 下面我这个代码没有写拷贝构造,它会自动生成一个默认的值拷贝,我们来运行一下

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2(s1);
	return 0;
}
  • 我们看到程序崩溃了~~

在这里插入图片描述

  • 也就是在一些场景下,默认生成的拷贝构造是会出事的

  • 再调试看一下:

在这里插入图片描述

  • 这会导致两个对象指向同一块空间

在这里插入图片描述

  • 在结束的时候会调用析构函数,会把那块空间给释放了

在这里插入图片描述

  • 再次释放的时候会出现错误
  • 同一块空间被释放了两次【所以是绝对不能的】

在这里插入图片描述

  • 正确的我们这样写
  • 需要引入一个叫做深拷贝
Stack(const Stack& s)
{
	// 深拷贝
	DataType* tmp = (DataType*)malloc(s._capacity * sizeof(DataType));
	if (nullptr == tmp)
	{
		perror("malloc fail\n");
		exit(-1);
	}
	memcpy(tmp, s._array, sizeof(DataType) * s._size);
	_array = tmp;
	// 浅拷贝
	_size = s._size;
	_capacity = s._capacity;
}

在这里插入图片描述

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

拷贝构造函数典型调用场景

  • 使用已存在对象创建新对象
  • 函数参数类型为类类型对象
  • 函数返回值类型为类类型对象
class Date
{
public:
	Date(int year, int minute, int day)
	{
		cout << "Date(int,int,int):" << this << endl;
	}
	Date(const Date& d)
	{
		cout << "Date(const Date& d):" << this << endl;
	}
	~Date()
	{
		cout << "~Date():" << this << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
Date Test(Date d)
{
	Date temp(d);
	return temp;
}
int main()
{
	Date d1(2022, 1, 13);
	Test(d1);
	return 0;
}

在这里插入图片描述

  • 为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用尽量使用引用。

最后本文就到这里结束了,感谢大家的收看,请多多指点~

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

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

相关文章

数值类型的运算方式总结

提纲1&#xff1a;常见的位运算使用场景 提纲2&#xff1a;整数类型运算时的类型溢出问题&#xff0c;产生原因以及解决办法 提纲3&#xff1a;浮点类型运算时的精度丢失问题&#xff0c;产生原因以及解决办法 数值类型&#xff08;6种&#xff09;分为&#xff1a; 整型&…

简易绘图软件(水一期)

哈哈&#xff01; 1、编写代码&#xff1a; 代码&#xff1a; main: #include <graphics.h> #include <music.h> #include <heker.h> #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )using…

【python】python入门(输出)

本篇文章将会介绍关于python的常见输出&#xff0c;希望对您有帮助&#xff01; 输出 用到print函数 print(oh mygod)##或者 print("oh mygod")##或者 print("oh"" ""mygod") 输出结果&#xff1a; 用单引号、双引号都可以 ,引号中可…

单片机学习笔记---LCD1602

LCD1602介绍 LCD1602&#xff08;Liquid Crystal Display&#xff09;液晶显示屏是一种字符型液晶显示模块&#xff0c;可以显示ASCII码的标准字符和其它的一些内置特殊字符&#xff08;比如日文的片假名&#xff09;&#xff0c;还可以有8个自定义字符 显示容量&#xff1a;…

Linux 幻兽帕鲁服务器怎么上传存档文件?

通过控制台远程连接到 Linux 服务器后&#xff0c;你可以打开文件树&#xff0c;然后找到幻兽帕鲁存档位置&#xff0c;将存档压缩包上传到 Pal 目录中。 记得替换存档前要先停止服务。 2. 然后将 Saved.tar 文件解压&#xff0c;并完全替换新服务器上的 Saved 存档目录即可。 …

蓝桥杯:C++排序

排序 排序和排列是算法题目常见的基本算法。几乎每次蓝桥杯软件类大赛都有题目会用到排序或排列。常见的排序算法如下。 第(3)种排序算法不是基于比较的&#xff0c;而是对数值按位划分&#xff0c;按照以空间换取时间的思路来排序。看起来它们的复杂度更好&#xff0c;但实际…

真假难辨 - Sora(OpenAI)/世界模拟器的技术报告

目录 引言技术报告汉译版英文原版 引言 Sora是OpenAI在2024年2月15日发布的世界模拟器&#xff0c;功能是通过文本可以生成一分钟的高保真视频。由于较高的视频质量&#xff0c;引起了巨大关注。下面是三个示例&#xff0c;在示例之后给出了其技术报告&#xff1a; tokyo-wal…

博途PLC While指令编程应用(SCL代码)

FOR循环和While指令都可以实现循环控制。在循环体内部&#xff0c;你可以编写需要重复执行的代码。WhIile在每次循环开始之前&#xff0c;都会检查条件是否为真。如果条件为真&#xff0c;则执行循环体内的代码&#xff1b;如果条件为假&#xff0c;则跳出循环&#xff0c;继续…

Android Studio 实现图书借阅(管理)系统

&#x1f345;文章末尾有获取完整项目源码方式&#x1f345; 目录 前言 一、任务介绍 1.1 背景 1.2目的和意义 二、 实现介绍 视频演示 2.1 启动页实现 2.2 注册页面实现 2.3 登陆页面实现 2.4 图书列表的实现 2.5 当前借阅页面实现 2.6 我的页面实现…

你知道.NET的字符串在内存中是如何存储的吗?

一、字符串对象的内存布局 从“值类型”和“引用类型”来划分&#xff0c;字符串自然属于引用类型的范畴&#xff0c;所以一个字符串对象自然采用引用类型的内存布局。引用类型实例的内存布局总的来说整个内存布局分三块&#xff1a;ObjHeader TypeHandle Payload。对于一般…

如何在Windows中配置多个显示器?这里提供详细步骤

Windows可以通过多种方式使用多个显示器,扩展或复制主显示器。你甚至可以关闭主显示器。以下是如何使用简单的键盘快捷键更改辅助显示设置。 使用Windows+P投影菜单 要快速更改Windows 10处理多个显示器的方式,请按Windows+P。屏幕右侧会弹出一个名为“投影”的深灰色菜单。…

Codeforces Round 926 F. Sasha and the Wedding Binary Search Tree

F. Sasha and the Wedding Binary Search Tree 题意 给定一颗二叉搜索树&#xff0c;规定树上的所有点的点权都在范围 [ 1 , C ] [1, C] [1,C] 内&#xff0c;树上的某些节点点权已知&#xff0c;某些节点点权未知&#xff0c;求出合法的二叉搜索树的数量 思路 由于是二叉搜…

Web项目利用MybatisPlus进行分页查询

之前在写博客系统前台页面的时候&#xff0c;遇到了利用mp进行分页查询的情况&#xff0c;由于涉及到的知识点相对较为重要&#xff0c;固写一篇博客以此巩固。 一、功能需求 在首页和分类页面都需要查询文章列表。 首页&#xff1a;查询所有的文章分类页面&#xff1a;查询…

隐函数的求导【高数笔记】

1. 什么是隐函数&#xff1f; 2. 隐函数的做题步骤&#xff1f; 3. 隐函数中的复合函数求解法&#xff0c;与求导中复合函数求解法有什么不同&#xff1f; 4. 隐函数求导的过程中需要注意什么&#xff1f;

透光力之珠——光耦固态继电器的独特特点解析

光耦固态继电器作为现代电子控制领域中的重要组件&#xff0c;以其独特的特点在工业、通信、医疗等多个领域得到广泛应用。本文将深入剖析光耦固态继电器的特点&#xff0c;揭示其在电子控制中的卓越性能。 光耦固态继电器的光电隔离技术 光耦固态继电器以其光电隔离技术而脱颖…

深入了解社区店:定义、模式与优势

在当今的商业环境中&#xff0c;社区店正逐渐成为创业者们关注的热点。本文将以我的鲜奶吧店铺为例&#xff0c;深入探讨社区店的定义、模式和优势&#xff0c;为您提供最有价值的干货信息。 1、社区店的定义 社区店是指位于社区内或周边&#xff0c;以服务社区居民为主要目标…

Diffusion Transformer U-Net for MedicalImage Segmentation

用于医学图像分割的扩散变压器U-Net 摘要&#xff1a; 扩散模型在各种发电任务中显示出其强大的功能。在将扩散模型应用于医学图像分割时&#xff0c;存在一些需要克服的障碍:扩散过程调节所需的语义特征与噪声嵌入没有很好地对齐;这些扩散模型中使用的U-Net骨干网对上下文信…

2.15学习总结

2.15 1.聪明的质监员&#xff08;二分前缀和&#xff09; 2.村村通&#xff08;并查集&#xff09; 3.玉蟾宫(悬线法DP) 4.随机排列&#xff08;树状数组逆序对问题&#xff09; 5.增进感情&#xff08;DFS&#xff09; 6.医院设置&#xff08;floyd&#xff09; 聪明的质监员…

P1010 [NOIP1998 普及组] 幂次方题解

题目 任何一个正整数都可以用2的幂次方表示。例如137。 同时约定次方用括号来表示&#xff0c;即ab可表示为a(b)。 由此可知&#xff0c;137可表示为2(7)2(3)2(0)&#xff0c;进一步&#xff1a;72 ( 用2表示)&#xff0c;并且32。 所以137可表示为2(2(2)22(0))2(22(0))2(0…

ESP32学习(4)——电脑远程控制LED灯

1.思路梳理 首先需要让ESP32连接上WIFI 然后创建udp socket 接着接收udp数据 最后解析数据&#xff0c;控制LED 2.代码实现 import network from socket import * from machine import Pin p2Pin(2,Pin.OUT)def do_connect(): #连接wifi wlan network.WLAN(network.STA_IF)…