类和对象(上续)
前言:本文介绍类和对象中的一些比较重要的知识点,为以后的继续学习打好基础。
目录
拷贝构造
拷贝构造的特征:
自定义类型的传值传参
自定义类型在函数中的传值返回
如果返回值时自定义的引用呢?
在什么情况下使用呢?
拷贝构造中的浅拷贝问题
编辑
为什么会释放两次呢?
那么什么情况下需要深拷贝?
运算符重载
运算符重载的基本语法:
类中运算符重载函数的调用的两种方法:
运算符重载与函数重载
运算符重载的特征:
运算符重载的价值:
如果将运算符重载成全局函数,就无法访问类中的私有成员了。
解决方法:
赋值运算符
调用拷贝构造与调用赋值重载的区别
拷贝构造
拷贝构造是一种特殊的构造函数
拷贝构造的特征:
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通常提供多种语言…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

