【C++第三课 - 类和对象中】构造函数、析构函数、拷贝构造函数

目录

  • 类的6个默认成员函数
    • 构造函数
      • 自己写的构造函数
      • 默认生成的构造函数
    • 析构函数
      • 概念
      • 特征
    • 拷贝构造函数
      • 特征
    • 运算符重载
      • == 、 >、 <=
      • +=
      • +
    • 赋值重载
    • Date类的完善
      • 构造函数的完善
      • 用+复用+=

类的6个默认成员函数

默认成员函数:不写编译器也会默认生成一份
在这里插入图片描述

构造函数

自己写的构造函数

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任
并不是开空间创建对象,而是初始化对象
其特征如下:

  1. 函数名与类名相同。
  2. 无返回值,不需要写void
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。
  5. . 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦
    用户显式定义编译器将不再生成。
  6. 关于编译器生成的默认成员函数,很多童鞋会有疑惑:不实现构造函数的情况下,编译器会
    生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默
    认构造函数,但是d对象_year/_month/_day,依旧是随机值。也就说在这里编译器生成的
    默认构造函数并没有什么用??
    解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类
    型,如:int/char…,自定义类型就是我们使用class/struct/union等自己定义的类型,看看
    下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员
    函数。
  7. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。
    注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为
    是默认构造函数。
#include <iostream>
using namespace std;class Date
{
public:Date(){_day = 1;_month = 1;_year = 1;}Date(int day, int month, int year){_day = day;_month = month;_year = year;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _day;int _month;int _year;
};int main()
{Date d1;Date d2(2023, 1, 24);d1.Print();d2.Print();return 0;
}

在这里插入图片描述

对于没有参数的初始化对象时,不能写成下面那样,因为无法与函数声明区分
Date d1()

也可以用缺省函数,下面两个函数构成函数重载,但是无参调用的时候会产生歧义

//Date()
//	{
//		_day = 1;
//		_month = 1;
//		_year = 1;
//	}Date(int day = 1, int month = 1, int year = 1){_day = day;_month = month;_year = year;}

默认生成的构造函数

默认构造函数:编译器默认生成的、无参的构造函数、全缺省的构造函数(可以不传参的都叫默认构造),这三个函数不能同时存在,因为会存在调用歧义。
如果不写构造函数,有没有构造函数
默认生成的,但此时是随机值

class Date
{
public:void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _day;int _month;int _year;
};int main()
{Date d1;d1.Print();return 0;
}

在这里插入图片描述
对于栈的初始函数来说,初始化的也是随机值

class Stack
{
public:private:int* _a;int _top;int _capacity;
};int main()
{Stack s1;return 0;
}

在这里插入图片描述
但对于像MyQueue的构造函数就初始化了
在这里插入图片描述

在这里插入图片描述
规则
内置类型:int/double/…指针,eg:Date* p是内置类型
自定义类型: class struct…
默认生成的构造函数,对于内置类型成员不做处理(看编译器,建议当成不处理),自定义类型会取调用它的默认构造(调用无参的默认构造,如果自定义类型没有默认构造 - 初始化列表,类和对象下讲)
对于这个缺陷C++11提供如下解决方法,下面这个写法还是声明,给的缺省值
在这里插入图片描述

析构函数

概念

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由
编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

特征

析构函数是特殊的成员函数,其特征如下:

  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构
    函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
  5. 编译器生成的默认析构函数,对自定类型成员调用它的析构函数。
  6. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如
    Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类
    日期类不需要写析构,栈需要写析构
class Date
{
public:Date(int day = 1, int month = 1, int year = 1){_day = day;_month = month;_year = year;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}~Date(){cout << "~Date()" << endl;}
private:int _day = 1;int _month = 1;int _year = 1;
};int main()
{Date d1;d1.Print();return 0;
}

在这里插入图片描述
在这里插入图片描述

拷贝构造函数

在这里插入图片描述
浅拷贝时,st和st1对象会导致对同一块空间的重复释放
解决方法:自定义类型对象拷贝时,调用一个函数,这个函数就叫拷贝构造 - 深拷贝。
(1)传参的时候
(2)初始化构造的时候Date d2(d1)

特征

  1. 拷贝构造函数是构造函数的一个重载形式
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错
    因为会引发无穷递归调用。.0
  3. 默认生成的拷贝构造函数:对内置类型会完成值拷贝,自定义对象回去调用它的拷贝对象。
    在这里插入图片描述
    像下面所示,st1与st中的_a是指向同一块空间,当这两个对象被释放时,会对_a所指的这段空间释放两次,从而造成错误,拷贝构造主要是解决这个问题的深拷贝
    在这里插入图片描述
    在这里插入图片描述
class Stack
{
public:Stack(){//...}Stack(const Stack& stt){_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;}
private:int* _a;int _top;int _capacity;
};

在这里插入图片描述

1、被拷贝的对象前面加const,防止意外的改变

运算符重载

对于+、-、*、/、>、<等等,内置类型可以直接使用,自定义类型无法使用
解决方法:(1)写一个函数 (2)使用运算符重载
运算符重载:operator+运算符 ,使用方法:直接使用运算符

函数重载:允许参数不同的同名函数存在
运算符重载:自定义类型可以直接使用运算符

== 、 >、 <=

class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}public:int _year;int _month;int _day;
};
bool operator==(Date x, Date y)
{return x._year == y._year && x._month == y._month && x._day == y._day;
}
bool operator>(Date x, Date y)
{if (x._year > y._year)return true;else if (x._year == y._year && x._month > y._month)return true;else if (x._year == y._year && x._month == y._month && x._day > y._day)return true;return false;
}
bool operator<=(Date x, Date y)
{return ~(x > y);
}int main()
{Date d1(2001, 3, 29);Date d2(2024, 3, 1);cout << (d1 > d2) << endl;cout << (d1 == d2) << endl;cout << (d1 <= d2) << endl;return 0;
}

在这里插入图片描述
报错的原因:因为流提取运算符的优先级大于>,因此加个括号就没事了
在这里插入图片描述
**此时程序的缺陷 :
1、运算符重载函数的参数那,调用了拷贝构造 --> 用&
2、为了在函数里访问类的成员变量,把成员变量设置 成了公有 --> 在类里面设置一些访问成员的函数;将运算符重载函数放到类里面
**
缺陷1修改

bool operator==(const Date& x, const Date& y)
{return x._year == y._year && x._month == y._month && x._day == y._day;
}
bool operator>(const Date& x, const Date& y)
{if (x._year > y._year)return true;else if (x._year == y._year && x._month > y._month)return true;else if (x._year == y._year && x._month == y._month && x._day > y._day)return true;return false;
}
bool operator<=(const Date& x, const Date& y)
{return ~(x > y);
}

缺陷2修改

class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}bool operator==(const Date& y){return _year == y._year && _month == y._month && _day == y._day;}bool operator>(const Date& y){if (_year > y._year)return true;else if (_year == y._year && _month > y._month)return true;else if (_year == y._year && _month == y._month && _day > y._day)return true;return false;}bool operator<=(const Date& y){return ~(*this > y);}private:int _year;int _month;int _day;
};

在这里插入图片描述
也可以d1.operator>(d2)这样显示的调用
这个类还可以些哪些运算符重载,这个取决于哪些运算符对于这个类是有意义的
eg:日期-日期、日期+=天数、日期+天数

+=

int GetMonthDay(int year, int month){assert(year >= 1 && month >= 1 && day >= 1);int arr[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 arr[month];}Date& operator+=(int day){_day += day;while (_day > GetMonthDay()){_day -= GetMonthDay();_month++;if (_month > 12){_year++;_month = 1;}}return *this;}

细节
根据内置类型的定义,+=是有返回值的,因此自定义类型也应该有返回值
在这里插入图片描述

在这里插入图片描述

+

int GetMonthDay(int year, int month){assert(year >= 1 && month >= 1 && day >= 1);int arr[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 arr[month];}
Date operator+(int day){Date tmp(*this);tmp._day += day;while (tmp._day > GetMonthDay(tmp._year, tmp._month)){tmp._day -= GetMonthDay(tmp._year, tmp._month);tmp._month++;if (tmp._month > 12){tmp._year++;tmp._month = 1;}}return tmp;}

赋值重载

operator= 我们不写,编译器回生成默认的operator=。跟拷贝构造的行为类似,内置类型值拷贝,自定义类型调用他的赋值
Date、MyQueue可以不用写,默认生成的operator=就可以用
赋值重载:(重载运算符)两个已经存在的对象拷贝
拷贝构造:一个已经存在的对象去拷贝初始化另一个对象

缺省参数不能同时出现在声明与定义里面,只能在声明中定义

Date& operator=(const Date& y);Date& Date::operator=(const Date& y)
{if (this != &y){_year = y._year;_month = y._month;_day = y._day;}return *this;
}

Date类的完善

构造函数的完善

Date::Date(int year = 1, int month = 1, int day = 1)
{_year = year;_month = month;_day = day;if (_year < 1 || _month > 13 || _month < 1 || day < 1 || day > GetMonthDay(_year, _month)){print();cout << "日期非法" << endl;}
}

用+复用+=

复用1

Date& Date::operator+=(int day)
{*this = *this + day;return *this;}
Date Date::operator+(int day)
{Date tmp(*this);tmp._day += day;while (tmp._day > GetMonthDay(tmp._year, tmp._month)){tmp._day -= GetMonthDay(tmp._year, tmp._month);tmp._month++;if (tmp._month > 12){tmp._year++;tmp._month = 1;}}return tmp;}

在这里插入图片描述

复用2

Date& Date::operator+=(int day)
{_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_year++;_month = 1;}}return *this;}
Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;}

在这里插入图片描述

复用2要比复用1效率更高

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

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

相关文章

UnityShader——09数学知识3

方阵 行与列数量相等的矩阵,n*n阶矩阵 对角矩阵 当对角线以外的矩阵内元素全为0&#xff0c;则称之为对角矩阵&#xff0c;对角矩阵的前提是必须是方阵 单位矩阵 对角线元素全为1&#xff0c;其余元素全为0&#xff0c;属于对角矩阵的一部分 矩阵和向量 把1 * n阶矩阵称…

多个地区地图可视化

1. 配置Json文件 1.1 获得每个省份的json数据 打开 阿里云数据可视化平台 主页。 在搜索框中输入所需省份。 将json文件下载到本地。 1.2 将各省份的json数据进行融合 打开 geojson.io 主页 点击 open&#xff0c;上传刚刚下载的 json 文件&#xff0c;对多个省份不断…

【CSP试题回顾】201409-1-相邻数对

CSP-201409-1-相邻数对 解题代码 #include <iostream> #include <vector> using namespace std;vector<int>arr; int num;int main() {ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);int n;cin >> n;for (int i 0; i < n; i){int t;…

不愧是华为出来的,太厉害了...

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 实习去了博彦科技&#xff08;外包&#xff09;&#xff0c;做的…

赋能中国制造,大道云行发布智能制造分布式存储解决方案

《中国制造2025》指出&#xff0c;“制造业是国民经济的主体&#xff0c;是立国之本、兴国之器、强国之基。” 智能制造引领产业提质增效 智能制造是一种利用先进的信息技术、自动化技术和智能技术来优化和升级制造业生产过程的方法。它将人工智能、大数据、物联网、机器学习等…

【扩散模型系列2】DiT 《Scalable Diffusion Models with Transformers》论文阅读

文章目录 摘要1. 前言2. 相关工作TransformersDDPMs架构复杂度 3. 扩散Transformer3.1 准备知识扩散公式Classifier-free GuidanceLDMs 3.2. Diffusion Transformer Design SpacePatch化DiT模块设计模型大小Transformer Decoder 4. 实验设置训练扩散评估指标计算 5. 实验DiT bl…

Material UI 5 学习01-按钮组件

Material UI 5 学习01-按钮组件 一、安装Material UI二、 组件1、Button组件1、基础按钮2、variant属性3、禁用按钮4、可跳转的按钮5、disableElevation属性6、按钮的点击事件onClick 2、Button按钮的颜色和尺寸1、Button按钮的颜色2、按钮自定义颜色3、Button按钮的尺寸 3、图…

MacOS包管理工具homebrew使用教程

MacOS包管理工具homebrew使用教程 1.概述与安装2.基本使用3.其他常用命令 1.概述与安装 homebrew是Mac OS X上的强大的包管理工具&#xff0c;可以高效管理各种软件包 安装&#xff1a; 1、安装xcode&#xff1a; xcode-select --install2、一行命令下载&#xff1a; /bin…

DreamTalk:单张图像即可生成逼真人物说话头像动画,助力AI数字人落地

“DreamTalk: When Expressive Talking Head Generation Meets Diffusion Probabilistic Models” DreamTalk是一个基于扩散的音频驱动的富有表现力的说话头生成框架&#xff0c;可以生成不同说话风格的高质量的说话头视频。DreamTalk对各种输入表现出强大的性能&#xff0c;包…

Thingsboard本地源码部署教程

本章将介绍ThingsBoard的本地环境搭建&#xff0c;以及源码的编译安装。本机环境&#xff1a;jdk11、maven 3.6.2、node v12.18.2、idea 2023.1、redis 6.2 环境安装 开发环境要求&#xff1a; Jdk 11 版本 &#xff1b;Postgresql 9 以上&#xff1b;Maven 3.6 以上&#xf…

【Java】Base理论的核心思想和理论三要素

目录 简介 BASE 理论的核心思想 BASE 理论三要素 1. 基本可用 2. 软状态 3. 最终一致性 总结 简介 BASE 是 Basically Available&#xff08;基本可用&#xff09; 、Soft-state&#xff08;软状态&#xff09; 和 Eventually Consistent&#xff08;最终一致性&#xf…

财报解读:基本盘稳定后,联想如何进一步抢占AI时代?

从2021年下半年开始&#xff0c;受诸多因素影响&#xff0c;消费电子行业始终处在承压状态&#xff0c;“不景气”这一关键词屡次被市场提及。 但寒气没有持续&#xff0c;可以看到&#xff0c;消费电子行业正在逐渐回暖。国金证券在今年1月的研报中就指出&#xff0c;从多方面…

#WEB前端(CCS常用属性,补充span、div)

1.实验&#xff1a; 复合元素、行内元素、块内元素、行内块元素 2.IDE&#xff1a;VSCODE 3.记录&#xff1a; span为行内元素&#xff1a;不可设置宽高&#xff0c;实际占用控件决定分布空间。 div为块内元素&#xff1a;占满整行&#xff0c;可以设置宽高 img为行内块元…

Unity(第二十三部)导航

你可以使用 unity官方提供的 unity导航组件或第三方 unity导航组件&#xff0c;以实现游戏中角色或其他物体的导航。 unity导航组件通常具有多种导航模式&#xff0c;如飞行模式、步行模式、车辆模式等&#xff0c;可以根据不同的需求选择合适的模式。同时&#xff0c;unity导…

2023年全国职业院校技能大赛中职组大数据应用与服务赛项题库参考答案陆续更新中,敬请期待…

2023年全国职业院校技能大赛中职组大数据应用与服务赛项题库参考答案陆续更新中&#xff0c;敬请期待… 武汉唯众智创科技有限公司 2024 年 2 月 联系人&#xff1a;辜渝傧13037102709 题号&#xff1a;试题01 模块二&#xff1a;数据获取与处理 &#xff08;一&#xff09;…

Ainx的全局配置

&#x1f4d5;作者简介&#xff1a; 过去日记&#xff0c;致力于Java、GoLang,Rust等多种编程语言&#xff0c;热爱技术&#xff0c;喜欢游戏的博主。 &#x1f4d7;本文收录于Ainx系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏Rust初阶教程、go语言基础系列…

【S32DS报错】-7-程序进入HardFault_Handler,无法正常运行

【S32K3_MCAL从入门到精通】合集&#xff1a; S32K3_MCAL从入门到精通https://blog.csdn.net/qfmzhu/category_12519033.html 问题背景&#xff1a; 在S32DS IDE中使用PEmicro&#xff08;Multilink ACP&#xff0c;Multilink Universal&#xff0c;Multilink FX&#xff09…

【网站项目】182在线作业管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【Python】进阶学习:pandas--describe()函数的使用介绍

&#x1f40d;【Python】进阶学习&#xff1a;pandas——describe()函数的使用介绍 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&am…

绘图机器 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 绘图机器的绘图笔初始位置在原点&#xff08;0, 0&#xff09;&#xff0c;机器启动后其绘图笔按下面规则绘制直线&#xff1a; 1&#xff09;尝试沿着横向坐标轴…