C++ 拷贝构造函数和运算符重载

目录

一. 拷贝构造函数

1. 引入

2. 拷贝构造的概念

3. 浅拷贝

4. 深拷贝

二. C++运算符重载 

1. 概念 

2. 注意事项 

3.举例 


一. 拷贝构造函数

1. 引入

我们在创建对象时,能不能创建一个与原先对象一模一样的新对象呢?为了解决这个问题,C++提出了拷贝构造的概念。

2. 拷贝构造的概念

当我们想把一个对象赋值给另一个对象或者创建一个与已存在对象一某一样的新对象时需要调用它的拷贝函数来进行复制。我们以下面的代码举例:

#include<iostream>
using namespace std;class Date 
{
public:Date(int year = 2024, int month = 3, int day = 14){_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);
//这样写也可以:Date d2 = d1;return 0;
}

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

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

2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用

为什么会引发无穷递归呢?是因为如果我们传值当形参的话那么形参是实参的一份临时拷贝又会拷贝构造函数这样就会无限递归下去。

所以我们在书写构造函数的时候一定要使用传引用当做形参。 

 

3. 浅拷贝

我们知道C语言函数在传递参数时,会将实参的值传递给形参,中间自动存在一个变量的临时拷贝过程,那如果我们不写拷贝构造函数,编译器会发生什么情况呢?

我们发现仍然完成了值拷贝。这是因为拷贝构造函数没有显示定义的化,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。需要注意的是,在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

4. 深拷贝

编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?我们来看下面的代码:

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;
}

这里刚开始创建了一个S1 对象,又创建了一个S2 对象去进行调用拷贝构造函数进行拷贝,而这里只进行了浅拷贝,在 S2 进行拷贝构造的时候只是简单的把值复制过去了所以 S2 和 S1 是指向同一块空间并没有给 S2 去单独开辟一个一模一样的空间。那为什么程序回出现崩溃呢?

S2 和 S1 指向用一块空间而当程序结束的时候 S2 调用它的析构函数去吧 S1 所指向的空间给释放了, 那么当 S1 在释放的时候就重复释放了原来释放的空间导致程序崩溃。一块空间不能被释放两次。

因此我们我们需要进行深拷贝:

#include<iostream>
#include<stdlib.h>
using namespace std;class Stack
{
public:Stack(size_t capacity = 10){_array = (int*)malloc(capacity * sizeof(int));if (nullptr == _array){perror("malloc申请空间失败");return;}_size = 0;_capacity = capacity;}Stack(const Stack& p1){int* tmp = (int*)malloc(sizeof(int) * p1._capacity);if (tmp == nullptr){perror("file malloc");exit(-1);			}memcpy(tmp, p1._array, sizeof(int) * p1._size);_array = tmp;_capacity = p1._capacity;_size = p1._size;}void Push(const int& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}
private:int* _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;
}

所以我们需要动态申请空间,显示定义拷贝构造函数,把空间大小和值内容拷贝进去。

因此我们有以下总结: 

类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请 时,则拷贝构造函数是一定要写的,否则就是浅拷贝。拷贝构造函数典型调用场景:使用已存在对象创建新对象 函数参数类型为类类型对象 ,函数返回值类型为类类型对象。

二. C++运算符重载 

1. 概念 

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其 返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。 函数名字为:关键字operator后面接需要重载的运算符符号。

函数原型:返回值类型 operator操作符(参数列表)

2. 注意事项 

 不能通过连接其他符号来创建新的操作符:比如operator@

重载操作符必须有一个类类型参数 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义

作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this

以上下个运算符不能重载:

3.举例 
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}int _year;int _month;int _day;
};bool operator==(const Date& d1, const Date& d2)
{return d1._year == d2._year&& d1._month == d2._month&& d1._day == d2._day;
}int main()
{Date d1(2024, 3, 14);Date d2(2024, 3, 15);cout << (d1 == d2) << endl;return 0;
}


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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

0304_数据可视化实战(一)

数据处理 安装openpyxl # 当前执行的命令是安装在该虚拟python环境中 !pip install openpyxl -i https://mirrors.aliyun.com/pypi/simple/数据查看 import pandas as pd fund pd.read_excel(./fund.xlsx) # 查看前10条数据 fund.head(10)姓名公司基金数量年天基金规模基金…

Windows系统搭建Cloudreve结合内网穿透打造可公网访问的私有云盘

目录 ⛳️推荐 1、前言 2、本地网站搭建 2.1 环境使用 2.2 支持组件选择 2.3 网页安装 2.4 测试和使用 2.5 问题解决 3、本地网页发布 3.1 cpolar云端设置 3.2 cpolar本地设置 4、公网访问测试 5、结语 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff…

1.leetcode---字符串中的第一个唯一字符(Java版)

链接在此: https://leetcode.cn/problems/first-unique-character-in-a-string/description/ 给定一个字符串 s &#xff0c;找到 它的第一个不重复的字符&#xff0c;并返回它的索引 。如果不存在&#xff0c;则返回 -1 。 示例 1&#xff1a; 输入: s “leetcode” 输出: 0…

阿里云 云盘扩容之后“不生效”处理办法

服务器只有一块40GB的系统盘&#xff08;/dev/vda1&#xff09;&#xff0c;目前已扩容到50GB&#xff0c;但是查看磁盘占用&#xff0c;还是没有变化 df -h [rootiZbp19utuqn2ezs6yevameZ www]# df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 868M…

三个表联合查询的场景分析-场景1:a表关联了b表和c表

本场景对应情景如下&#xff1a; 三个数据表&#xff0c;一个表的两个字段分别关联了另外两个表各自的id数据&#xff0c;可能包含多个id&#xff08;两个1对多关联&#xff09;。 目录 数据表准备 需求1、查询c表的列表数据&#xff0c;要求获得关联的b表中的name&#xf…

蓝桥杯第十一届电子类单片机组程序设计

目录 前言 单片机资源数据包_2023&#xff08;点击下载&#xff09; 一、第十一届比赛原题 1.比赛题目 2.赛题解读 1&#xff09;计数功能 2&#xff09;连续按下无效按键 二、部分功能实现 1.计数功能的实现 2.连续按下无效按键的处理 3.其他处理 1&#xff09;对于…

vue-draggable-resizable配合vue-plugin-hiprint实现移动输入框(或者其他东西)打印

思路 vue-plugin-hiprint打印只能打印模板&#xff08;不选择打印范围&#xff0c;因为控制不好位置&#xff0c;所以采用vue-plugin-hiprint自带的打印功能&#xff09;&#xff0c;然后就通过让移动输入框有个父盒子并且输入框怎样移动都不能越过父盒子&#xff0c;所以让这…

SpringCloud Bus 消息总线

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第八篇&#xff0c;即介绍 Bus 消息总线。 二、概述 2.1 遗留的问题 在上一篇文章的最后&#xff0c;我…

网络架构层_服务器上下行宽带

网络架构层_服务器上下行宽带 解释一 云服务器ECS网络带宽的概念、计费、安全及使用限制_云服务器 ECS(ECS)-阿里云帮助中心 网络带宽是指在单位时间&#xff08;一般指的是1秒钟&#xff09;内能传输的数据量&#xff0c;带宽数值越大表示传输能力越强&#xff0c;即在单位…

汇总全网免费API,持续更新(新闻api、财经、音乐。。。)

Public&FreeAPI 网址&#xff1a;apis.whyta.cn UomgAPI 网址&#xff1a;https://api.uomg.com 接口大全 网址&#xff1a;https://www.free-api.com 阿里云api市场 网址&#xff1a;https://market.aliyun.com/data 总结 如果需要更稳定的api&#xff0c;推荐…

strncat 函数

函数理解记忆&#xff1a;str表示的是该函数为string.h里的函数。nnat比strcat多了一个n表示是有数量number的追加。 函数的传入值和返回值&#xff1a; char* strncat( char*brr,char*arr,size_t n); 分别传入被追加的字符串&#xff0c;追加的字符串&#xff0c;追加字符串…

安装mysql到免费DataGrip保姆级教程

由于本教程是全过程&#xff0c;齐全到每一步都有&#xff0c;所以更多的是图片&#xff0c;所以只需要根据图片每一步操作即可&#xff0c;篇幅有点长&#xff0c;见谅。 目录 1&#xff0c;安装mysql 2&#xff0c;环境配置 3&#xff0c;安装DataGrip 4&#xff0c;配置…