类和对象(上续)
前言:本文介绍类和对象中的一些比较重要的知识点,为以后的继续学习打好基础。
目录
拷贝构造
拷贝构造的特征:
自定义类型的传值传参
自定义类型在函数中的传值返回
如果返回值时自定义的引用呢?
在什么情况下使用呢?
拷贝构造中的浅拷贝问题
编辑
为什么会释放两次呢?
那么什么情况下需要深拷贝?
运算符重载
运算符重载的基本语法:
类中运算符重载函数的调用的两种方法:
运算符重载与函数重载
运算符重载的特征:
运算符重载的价值:
如果将运算符重载成全局函数,就无法访问类中的私有成员了。
解决方法:
赋值运算符
调用拷贝构造与调用赋值重载的区别
拷贝构造
拷贝构造是一种特殊的构造函数
拷贝构造的特征:
1.是构造函数的重载
2.参数只有一个并且只能是引用
3.拷贝构造可以不显示写,编译器会自动生成默认构造。
浅拷贝(值拷贝)就是一个字节一个字节的拷贝。
编译器自动生成的默认拷贝的特点:对内置类型的成员,浅拷贝(值拷贝);对自定义类型的成员,拷贝需要调用其拷贝构造
#include <iostream>
using namespace std;
class Date
{
public:Date(int year,int month,int day){_year = year;_month = month;_day = day;}//拷贝构造Date(Date& d){cout << "拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2024,6,10);Date d2(d1);//拷贝构造Date d3 = d2;//拷贝构造return 0;
}
自定义类型的传值传参
#include <iostream>
using namespace std;
class Date
{
public:int GetYear(){return _year;}int GetMonth(){return _month;}int GetDay(){return _day;}Date(int year,int month,int day){_year = year;_month = month;_day = day;}Date(Date& d){cout << "拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};void f(Date d)
{cout << d.GetYear() << " " << d.GetMonth() << " " << d.GetDay() << endl;
}
int main()
{Date d1(2024,6,10);Date d2(d1);Date d3 = d2;f(d1);return 0;
}
以上代码的运行结果

在给f函数传值传参时,调用了一次拷贝构造。
结论:自定义类型在进行传值传参时会进行拷贝构造。
如果拷贝构造的参数是自定义类型而不是自定义的引用那么就会出现无穷递归调用。

![]()
自定义类型在函数中的传值返回
下面有一段代码,以这段代码为例讲一下该问题。
#include <iostream>
using namespace std;class Date
{public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};Date f(Date d)
{return d;
}int main()
{Date d1(2024, 6, 10);Date d2 = f(d1);return 0;
}
结论:如果返回值,是自定义类型,那么,返回时就会进行拷贝构造,创建临时对象,再将临时对象赋值给正在创建的类。
用一段错误代码解释上面的结论:
Date f(Date& d)
{return d;
}int main()
{Date d1(2024, 6, 10);Date& d2 = f(d1);return 0;
}
上述错误代码的报错:
原因是因为,临时对象具有常性,用d2来引用临时对象是会出现权限放大的问题,所以验证了上述的结论,如果加上const(权限平移)报错就会消失。

而编译器为了提高效率往往会直接将其优化为一次拷贝构造。

如果返回值时自定义的引用呢?
Date& f()
{Date d1(2023, 1, 2);return d1;
}int main()
{Date& d1 = f();return 0;
}
![]()
因为,d1 实在函数中定义的对象,出了函数的作用域就会销毁。
从栈帧的角度来理解,引用的本质是指针,f函数被销毁了,main函数中的d1仍指向f中的d1的那块已被销毁的空间

自定义类型的引用返回存在风险
在什么情况下使用呢?
出了函数的作用域,生命周期没到,不构析,对象还在,,那么就可以用引用 返回
出了函数的作用域,生命周期到了,析构,对象不存在,那么就只能用传值返回
拷贝构造中的浅拷贝问题
以下代码存在浅拷贝问题
#include <stdlib.h>
#include <iostream>
using namespace std;
class Stack
{
public:Stack(int capacity = 4){cout << "Stack()" << endl;_arr = (int*)malloc(sizeof(int) * capacity);_capacity = capacity;_top = 0;}~Stack(){cout << "~Stack()"<<endl;free(_arr);_capacity = 0;_top = 0;}
private:int* _arr;int _top;int _capacity;
};int main()
{Stack st1(4);Stack st2(st1);return 0;
}
程序崩溃:

该代码的问题就在于对一块开辟的空间释放两次。
为什么会释放两次呢?
因为没有显示写拷贝构造函数,所以用的是编译器自动生成的拷贝构造函数(浅拷贝),所以在拷贝构造st2时,使st2中_arr指向的空间与st1中的一样,最后分别调用析构函数时,就造成了对用一块开辟的空间释放两次。
解决方案就是深拷贝:
Stack(Stack& st){_arr = (int*)malloc(sizeof(int) * st._capacity);//深拷贝_capacity = st._capacity;_top = st._top;}
那么什么情况下需要深拷贝?
总结:
1.如果没有管理资源,就不显示写拷贝构造,用默认拷贝构造就可以
2.都是自定义的成员,内置类型(内置类型不指向资源),也用默认拷贝;如果自定义类型的成员的内置类型指向资源,那么在该自定义类型中显示写拷贝构造
3.一般,不需要写析构函数,就需要写构造函数
4.内部有指针或一些值指向资源,显示写析构释放,通常需要写拷贝构造来完成深拷贝
运算符重载
运算符重载的基本语法:
返回值类型 + operater+运算符(参数列表)
operator是关键字,operator和运算符一起构成函数名。
类中运算符重载函数的调用的两种方法:
//在类中实现的+运算符重载(实现日期与天数的相加)Date operator+(int day){_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_month = 1;_year++;}}return *this;} //已经在类中写了一个加号重载的函数Date d1(2024, 6, 10);d1 + 100;//第一种调用方法d1.operator+(100);//第二种调用方法
运算符重载与函数重载
运算符重载和函数重载没有关系,是两回事,而多个相同的运算符的重载是函数重载。
比如<<(流插入)可以自动识别内置类型的原因就是对<<进行重载,构成了函数重载。
运算符重载的特征:
1.不能通过其他符号重载
2.必须有一个类类型的参数
3.含义不能改变(这里是建议,比如重载的+的含义是将两个数相加,而你写的含义是相减)
4.一般,参数比运算符操纵的操作数的数目少1,因为在参数列表中有隐含的this指针
5. .* :: sizeof ?: . 这五个操作符不能被重载,.*是用于类成员函数指针的访问,
如果想了解:函数指针到底需不需要解引用?类成员函数呢?_函数指针需要解引用吗-CSDN博客
运算符重载的价值:
运算符重载是运算符不仅限于操纵内置类型的数据,可以实现类与类之间,或类与内置类型直间的运算,可以增强代码的可读性。
一个使用运算符重载的例子:
#include <iostream>
using namespace std;
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}//得到当前月份的天数int GetMonthDay(int year, int month){int month_day[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if(month==2&&((year%4==0&&year%100!=0)||year%400==0))return 29;return month_day[month];}//重载+运算符实现日期与天数的相加Date operator+(int day){_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_month = 1;_year++;}}return *this;}void Print(){cout << _year << " " << _month << " " << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2024, 6, 10);Date d2 = d1 + 100;d2.Print();return 0;
}
上述代码中的+的重载,是在类中实现的,或在类中声明,在类外实现。
如果将运算符重载成全局函数,就无法访问类中的私有成员了。
解决方法:
1.在类中实现成员的Get(获取成员)和Set(重新给成员赋值)的接口
2.将全局函数设为该类的友元
3.重载为成员函数(可以访问类的成员,但函数不在是全局函数)
这些方法比较建议第二种。
以下的代码是通过友元来实现全局减号的运算符重载
#include <iostream>
using namespace std;
class Date
{//友元就是在函数前加上一个关键字friend,并在相应的类中声明friend Date operator-(Date& d,int day);
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}int GetMonthDay(int year, int month){int month_day[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if(month==2&&((year%4==0&&year%100!=0)||year%400==0))return 29;return month_day[month];}Date operator+(int day){_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_month = 1;_year++;}}return *this;}void Print(){cout << _year << " " << _month << " " << _day << endl;}
private:int _year;int _month;int _day;
};//全局函数减号的重载
Date operator-(Date& d,int day)
{d._day -= day;while (d._day <= 0){if (d._month == 1){d._month = 12;d._year--;}else{d._month--;}d._day += d.GetMonthDay(d._year, d._month);}return d;
}
赋值运算符
赋值运算符重载也是6个默认成员函数之一。
调用拷贝构造与调用赋值重载的区别
Date d1(2024, 6, 10);Date d2 = d1;//拷贝构造Date d3(d1);//拷贝构造Date d4(2024, 2, 11);d4 = d1;//赋值重载
注意:上面代码中两个等号的调用方式容易混,但最后这两个有本质的区别。

结语:希望本文能够让你有所收获 。
相关文章:
类和对象(上续)
前言:本文介绍类和对象中的一些比较重要的知识点,为以后的继续学习打好基础。 目录 拷贝构造 拷贝构造的特征: 自定义类型的传值传参 自定义类型在函数中的传值返回 如果返回值时自定义的引用呢? 在什么情况下使用呢&#…...
【C++初阶学习】第十三弹——优先级队列及容器适配器
C语言栈:数据结构——栈(C语言版)-CSDN博客 C语言队列:数据结构——队列(C语言版)-CSDN博客 C栈与队列:【C初阶学习】第十二弹——stack和queue的介绍和使用-CSDN博客 前言: 在前面,我们已经…...
Java(十七)---ArrayList的使用
文章目录 前言1.ArrayList的简介2. ArrayList使用2.1.ArrayList的构造2.2.ArrayList的扩容机制(JDK17) 3.ArrayList的常见操作4. ArrayList的具体使用4.1.[杨辉三角](https://leetcode.cn/problems/pascals-triangle/description/)4.2.简单的洗牌游戏 5.ArrayList的问题及思考 …...
实验六、IPv4 地址的子网划分,第 2 部分《计算机网络》
你有没有发现,困的时候真的清醒不了。 目录 一、实验目的 二、实验内容 三、实验小结 一、实验目的 完成本练习之后,您应该能够确定给定 IP 地址和子网掩码的子网信息。 知道 IP 地址、网络掩码和子网掩码后,您应该能够确定有关该 IP 地…...
定个小目标之刷LeetCode热题(12)
这是一道简单题,使用位运算中的异或运算即可,异或运算有以下性质: 1、任何数异或 0 结果仍然是原来的数,即 a⊕0a 2、任何数和其自身做异或运算,结果是 0 所以我们只需要让数组里的所有元素进行异或运算得到的结果就…...
MYSQL内存占用查询语句
可以通过以下 SQL 语句查询相关配置参数的当前值: InnoDB 缓冲池大小 (innodb_buffer_pool_size): SHOW VARIABLES LIKE innodb_buffer_pool_size;最大连接数 (max_connections): SHOW VARIABLES LIKE max_connections;临时表大小 (tmp_table…...
HikariCP连接池初识
HikariCP的简单介绍 hikari-光,hikariCP取义:像光一样轻和快的Connetion Pool。这个几乎只用java写的中间件连接池,极其轻量并注重性能,HikariCP目前已是SpringBoot默认的连接池,伴随着SpringBoot和微服务的普及&…...
LeetCode136只出现一次的数字
题目描述 给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。 解析 需要想到异或运算&#…...
html5实现端午节网站源码
文章目录 1.设计来源1.1 端午首页页面1.2 端午由来页面1.3 端午图集页面1.4 端午活动页面1.5 给我留言页面 2.效果和源码2.1 动态效果2.2 目录结构 源码下载 作者:xcLeigh 文章地址:https://blog.csdn.net/weixin_43151418/article/details/139524377 ht…...
echarts组件x轴坐标显示不全解决方法
1.旋转: 修改前: option {xAxis: {type: category,data: [Mon, Tue, Wed, Thu, Fri, Sat, Sun,Mon, Tue, Wed, Thu, Fri, Sat, Sun,Mon, Tue, Wed, Thu, Fri, Sat, Sun]},yAxis: {type: value},series: [{data: [120, 200, 150, 80, 70, 110, 130,120, 200, 150, 80, 70, 1…...
JS实现移动端的轮播图滑动事件
在移动端实现轮播图滑动事件,我们通常使用 touchstart、touchmove 和 touchend 这三个事件。下面是一个基本的示例,展示了如何使用原生JavaScript来创建一个简单的移动端轮播图滑动效果: HTML结构: <div id"carousel&qu…...
2024.6.10学习记录
1、代码随想录二刷 2、项目难点 review 3、计组复习...
RapidJSON
要在项目中使用 RapidJSON 库,需要首先下载并包含该库的头文件。以下是详细的步骤,包括如何下载、引用和使用 RapidJSON: 使用 CMake 引用 RapidJSON 如果你的项目使用 CMake 构建系统,可以按照以下步骤引用 RapidJSONÿ…...
二叉树的创建
目录 一、二叉树的定义 二、代码定义 三、遍历二叉树 1、前序遍历 2、中序遍历 3、后序遍历 四、方法的使用 一、二叉树的定义 二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为&a…...
adb shell进入设备后的命令
目录 一、查看删除手机 /data/local/tmp/下的文件 二、设置权限 三、查看手机设备正在运行的服务 四、可能需要的adb 命令 一、查看删除手机 /data/local/tmp/下的文件 可以通过以下命令: adb shell # 进入设备 ls /data/local/tmp/ # 查看文件夹下的内容…...
【Android面试八股文】Java中静态内部类是什么?和非静态内部类的区别是什么?
文章目录 Java中静态内部类是什么?和非静态内部类的区别是什么?这道题想考察什么?考察的知识点考生应该如何回答什么是内部类,什么是静态内部类?静态内部类非静态内部类静态内部类和非静态内部类的区别静态内部类和普通内部类都有各自的用途和优势扩展一:使用静态内部类来…...
IDEA启动项目报java.lang.OutOfMemoryError: GC overhead limit exceeded
idea编译项目时报j ava.lang.OutOfMemoryError: GC overhead limit exceeded错误,教你两步搞定! 第一步:打开help -> Edit Custom VM Options ,修改xms和xmx的大小,如下图: 第二步:File -> Settings…...
基于R语言BIOMOD2 及机器学习方法的物种分布模拟与案例分析
原文链接:基于R语言BIOMOD2 及机器学习方法的物种分布模拟与案例分析https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247606139&idx4&snf94ec30bfb5fa7ac0320403d49db3b66&chksmfa821e9ccdf5978a44a9ba96f6e04a121c0bbf63beea0940b385011c0b…...
【笔记2】Python编程:从入门到实践(第2版) - 埃里克·马瑟斯
第二部分 1、外星人入侵 Pygame包 2、数据可视化 Matplotlib 、Plotly 3、Web应用程序 Django 项目1:外星人入侵 第12章~第14章 使用Pygame包来开发一款2D游戏。 它在玩家每消灭一群向下移动的外星人后,将玩家提高一个等级。等级越高&…...
优质免费的 5 款翻译 API 接口推荐
当谈到翻译API时,我们通常指的是一种编程接口,它允许开发者将文本从一种语言翻译成另一种语言。这些API通常由专业的翻译服务提供商提供,如谷歌翻译 API、实时翻译API、腾讯翻译API、DeepL翻译API、Azure翻译API等。 这些API通常提供多种语言…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...

