c++的学习之路:6、类和对象(2)

一、 构造函数

如果一个类什么成员都没有,那么他是一个空类吗?在c++的创建时,就规定了在类没有成员时,也会有六个默认的成员,简称6个默认成员函数,如下图所示

先介绍一下构造函数,这里就利用代码的演示来解释,这里是利用日期类来介绍的,如下代码就是正常的初始化,利用Init函数进行的初始化。

对于这个日期类来说每次都利用Init去初始化会显得很麻烦,这时c++的创造着就提出了一个函数叫做构造函数,这个函数主要就是在创建这个类的时候就进行初始化。

class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Init(2024, 3, 28);Date d2;d2.Init(2023, 3, 28);return 0;
}

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

如下代码所示就是创建的构造函数,构造函数是可以重载的,这里定义了两个,一个是没给参数,创建的可以看出是个随机值,一个是传参创建的是我想要的结果,可以得出构造函数可以重载是正确的,在创建时自动调用了,那么在创建类的时候没有参数可以像第二个构造函数一样吗?可以在后面加上括号吗?如图二看出创建d3的时候警告了,所以是不可以的。

class Date
{
public:Date(){}Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2(2024, 3, 28);return 0;
}

 如果不写构造函数那么会自动创建构造函数吗?从下面的图一看出只是发出警告,但是编译可以通过,只是再把构建函数加上我发现反而编译不通过了如图二,只是因为在类里面没有构造函数时,编译器自动生成了一个,但是在我加上后反而会因为找不到编译器默认生成的构造函数而报错。


class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};int main()
{Date d1;return 0;
}

 那么构造函数可以向函数一样进行缺省吗 ?如图所示是可以进行缺省的,那么可以部分缺省吗?答案也是可以的

 

class Date
{
public:Date(int year = 2024, int month = 3, int day = 28){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};int main()
{Date d1;return 0;
}

二、析构函数

析构函数和构造函数是一对的,与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。析构函数名是在类名前加上字符 ~。无参数无返回值类型。一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载,对象生命周期结束时、C++编译系统系统自动调用析构函数。这里就用栈来举例了,在创建栈的时候时是需要进行申请空间的,所以在程序结束时会自动调用吗?

如下代码和图可以看出在程序结束时是自动调用了析构函数,可以从图中看到,c++中是可以创造默认的析构函数时,如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如日期类;有资源申请时,一定要写,否则会造成资源泄漏,比如栈类。

typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 4){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc fail");return;}_capacity = capacity;_size = 0;}void Push(DataType data){_array[_size] = data;_size++;}~Stack(){cout << "~Stack()" << endl;if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};void Test1()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2;s2.Push(1);s2.Push(2);s2.Push(3);s2.Push(4);
}int main()
{Test1();return 0;
}

三、拷贝构造函数

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

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

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

3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

如下面代码被屏蔽的那一行可以看出在拷贝构造的过程中可以看出不用引用的符号就是会报错,因为他会无限的递归下去,在传值的底层中就是先拷贝一份,然后在赋值过去,这样传值就会无限的拷贝下去。如下方图二就可以看出在引用后就会正常拷贝进行构造了。

紧接着就是默认生成的拷贝构造,这个拷贝构造的就是浅拷贝,这个拷贝就是和构造函数一样,只能进行内置类型的拷贝,也就是int char 这种类型的,像栈这种的需要自己创建类型的就需要自己写的这种拷贝构造了,也就是深拷贝。

class Date
{
public:Date(int year = 204, int month = 3, int day = 28){_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);return 0;
}

四、 赋值运算符重载

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

函数名字为:关键字operator后面接需要重载的运算符符号。

但是要注意以下几点:

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

2、重载操作符必须有一个类类型参数

3、用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义

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

5、.*   ::  sizeof  ?:   . 注意以上5个运算符不能重载

如下方代码所示就是写的一个判断是否等于,注意下这里不需要改变数值,所以运用const修饰加上引用可以增加效率,这里就不一一演示各种符号了,在文章末会附上各种符号的写法。

class Date
{
public:Date(int year = 204, int month = 3, int day = 28){_year = year;_month = month;_day = day;}Date(const Date& d) {_year = d._year;_month = d._month;_day = d._day;}bool operator==(const Date& d){return _year == d._year && _month == d._month && _day == d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2(d1);if (d1 == d2){cout << "d1==d2" << endl;}return 0;
}

 那么前置++和后置++如何实现呢,前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载 C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递,注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存一份,然后给this+1,而temp是临时对象,因此只能以值的方式返回,不能返回引用,如下代码和下图所示在d1++是后++所以先给d1,然后d2就是28,然后d1变成29,然后前置++就是变成30,d3就是30。

class Date
{
public:Date(int year = 204, int month = 3, int day = 28){_year = year;_month = month;_day = day;}Date(const Date& d) {_year = d._year;_month = d._month;_day = d._day;}bool operator==(const Date& d){return _year == d._year && _month == d._month && _day == d._day;}Date& operator++(){_day += 1;return *this;}Date operator++(int){Date temp(*this);_day += 1;return temp;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2;Date d3;d2 = d1++;d3 = ++d1;return 0;
}

五、const成员函数

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数
隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改,如下方代码和图片显示,就可以看出在调用const后就会调用对应的函数,这样就不会改变类的数据。

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << "Print()" << '-';cout << "year:" << _year << '-';cout << "month:" << _month << '-';cout << "day:" << _day << endl << endl;}void Print() const{cout << "Print()const" << '-';cout << "year:" << _year << '-';cout << "month:" << _month << '-';cout << "day:" << _day << endl << endl;}
private:int _year; int _month; int _day; 
};
int main()
{Date d1(2024, 3, 28);d1.Print();const Date d2(2024, 3, 28);d2.Print();return 0;
}

六、日期类

日期类的代码放在这里了,测试结果如图

 test.cpp

#include "Date.h"void Test1()
{Date d1(2023,3,28);Date d2(2000,1,1);Date d3;d1.Print();d2.Print();d3.Print();d3 = d3 + 100;d3.Print();d3 = d3 - 50;d3.Print();d3 += 100;d3.Print();d3 -= 50;d3.Print();d3 = d2++;d3.Print();d3 = ++d2;d3.Print();d3 = d2--;d3.Print();d3 = --d2;d3.Print();if (d1 > d2){cout << "d1>d2" << endl;}else{cout << "d1<d2" << endl;}if (d3 < d1){cout << "d3<d1" << endl;}else{cout << "d3>d1" << endl;}if (d3 == d2){cout << "d3==d2" << endl;}else{cout << "d3!=d2" << endl;}if (d3 != d1){cout << "d3!=d1" << endl;}else{cout << "d3==d1" << endl;}
}int main()
{Test1();return 0;
}

Date.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"// 全缺省的构造函数
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}
// 拷贝构造函数
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}
// 析构函数
Date::~Date()
{_year = 0;_month = 0;_day = 0;
}
// 赋值运算符重载
Date& Date::operator=(const Date& d)
{if (this!=&d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}
// 日期+=天数
Date& Date::operator+=(int day)
{if (day < 0){return *this -= (-day);}_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);++_month;if (_month == 13){++_year;_month = 1;}}return *this;
}
// 日期+天数
Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;
}
// 日期-天数
Date Date::operator-(int day)
{Date tmp(*this);tmp -= day;return tmp;
}
// 日期-=天数
Date& Date::operator-=(int day)
{if (day < 0){return *this += (-day);}_day -= day;while (_day <= 0){--_month;if (_month == 0){--_year;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}
// 前置++
Date& Date::operator++()
{*this += 1;return *this;
}
// 后置++
Date Date::operator++(int)
{Date tmp(*this);*this += 1;return tmp;
}
// 后置--
Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}
// 前置--
Date& Date::operator--()
{*this -= 1;return *this;
}
// <运算符重载
bool Date::operator < (const Date& d)
{if (_year < d._year){return true;}else if (_year == d._year && _month < d._month){return true;}else if (_year == d._year && _month == d._month && _day < d._day){return true;}else{return false;}
}
// ==运算符重载
bool Date::operator==(const Date& d)
{return _year == d._year&& _month == d._month&& _day == d._day;
}
// <=运算符重载
bool Date::operator <= (const Date& d)
{return *this < d || *this == d;
}
// !=运算符重载
bool Date::operator != (const Date& d)
{return !(*this == d);
}
// >运算符重载
bool Date::operator>(const Date& d)
{return !(*this <= d);
}
// >=运算符重载
bool Date::operator >= (const Date& d)
{return !(*this < d);
}
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{Date max = *this;Date min = d;int flag = 1;if (*this < d){max = d;min = *this;flag = -1;}int n = 0;while (min != max){++min;++n;}return n * flag;
}
// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31 };int day = days[month];if (month == 2&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))){day += 1;}return day;
}
//打印
void Date::Print()
{cout << "Print:" << _year << '/' << _month << '/' << _day << endl << endl;
}

Date.h

#pragma once
#include <iostream>
using namespace std;class Date
{
public:// 获取某年某月的天数int GetMonthDay(int year, int month);// 全缺省的构造函数Date(int year = 1, int month = 1, int day = 1);// 拷贝构造函数Date(const Date& d);// 赋值运算符重载Date& operator=(const Date& d);// 析构函数~Date();// 日期+=天数Date& operator+=(int day);// 日期+天数Date operator+(int day);// 日期-天数Date operator-(int day);// 日期-=天数Date& operator-=(int day);// 前置++Date & operator++();// 后置++Date operator++(int);// 后置--Date operator--(int);// 前置--Date& operator--();// >运算符重载bool operator>(const Date& d);// ==运算符重载bool operator==(const Date& d);// >=运算符重载bool operator >= (const Date& d);// <运算符重载bool operator < (const Date& d);// <=运算符重载bool operator <= (const Date& d);// !=运算符重载bool operator != (const Date& d);// 日期-日期 返回天数int operator-(const Date& d);//打印void Print();
private:int _year;int _month;int _day;
};

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

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

相关文章

第四百三十六回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 实现方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"不同平台上换行的问题"相关的内容&#xff0c;本章回中将介绍如何在页面上显示蒙板层.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我…

鸿蒙OS开发实例:【ArkTS类库多线程CPU密集型任务TaskPool】

CPU密集型任务是指需要占用系统资源处理大量计算能力的任务&#xff0c;需要长时间运行&#xff0c;这段时间会阻塞线程其它事件的处理&#xff0c;不适宜放在主线程进行。例如图像处理、视频编码、数据分析等。 基于多线程并发机制处理CPU密集型任务可以提高CPU利用率&#x…

AMD GPUs - Radeon™ PRO W7900与NVIDIA 4000系列GPU性能

文心一言 RTX 4090的性能高于AMD Radeon PRO W7900。 RTX 4090具有760亿个晶体管、16384个CUDA核心和24GB高速镁光GDDR6X显存&#xff0c;在4K分辨率的游戏中持续以超过100FPS运行。RTX 4090采用全新的DLSS 3技术&#xff0c;相比3090TI&#xff0c;性能提升可达2~4倍&#x…

STM32F103 CubeMX 使用USB生成键盘设备

STM32F103 CubeMX 使用USB生成键盘设备 基础信息HID8个数组各自的功能 生成代码代码编写添加申明信息main 函数编写HID 修改1. 修改报文描述符2 修改 "usbd_hid.h" 中的申明文件 基础信息 软件版本&#xff1a; stm32cubmx&#xff1a;6.2 keil 5 硬件&#xff1a;…

超分辨率(4)--基于A2N实现图像超分辨率重建

一.项目介绍 已有研究表明&#xff0c;注意力机制对高性能超分辨率模型非常重要。然而&#xff0c;很少有工作真正讨论“为什么注意力会起作用&#xff0c;它又是如何起作用的”。 文章中尝试量化并可视化静态注意力机制并表明&#xff1a;并非所有注意力模块均有益。提出了…

vue3+threejs新手从零开发卡牌游戏(二十):添加卡牌被破坏进入墓地逻辑

在game目录下新建graveyard文件夹存放墓地相关代码&#xff1a; game/graveyard/p1.vue&#xff0c;这里主要设置了墓地group的位置&#xff1a; <template><div></div> </template><script setup lang"ts"> import { reactive, ref,…

Python入门(八)

引入 引入函数 为了减少代码的冗余&#xff0c;减轻我们的工作量&#xff0c;我们常常将代码分块编写&#xff0c;在Python中更是如此&#xff0c;那么我们怎么在一个新的程序文件中调用我们已经编写好程序文件的函数&#xff0c;我们使用import。我们先写一个first.py为例语…

WinForm_初识_事件_消息提示

文章目录 WinForm开发环境的使用软件部署的架构B/S 架构应用程序C/S 架构应用程序 创建 Windows 应用程序窗口介绍查看设计窗体 Form1.cs 后台代码窗体 Form1.cs窗体的常用属性 事件驱动机制事件的应用事件的测试测试事件的级联响应常用控件的事件事件响应的公共方法 消息提示的…

CCIE-02-PPPoE

目录 实验条件网络拓朴实验目标 开始配置R1验证效果 实验条件 网络拓朴 实验目标 R2为PPPoE Server&#xff0c;已预配了相关信息&#xff1b;R1作为PPPoE Client&#xff0c;进行PPPoE拨号 用户名为R1&#xff0c;密码为cisco &#xff0c; 采用CHAP的认证方式&#xff0c;I…

算法学习——LeetCode力扣补充篇3(143. 重排链表、141. 环形链表、205. 同构字符串、1002. 查找共用字符、925. 长按键入)

算法学习——LeetCode力扣补充篇3 143. 重排链表 143. 重排链表 - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为&#xff1a; L0 → Ln → …

Python学习笔记 - 如何在google Colab中显示图像?

这里是使用的opencv进行图片的读取&#xff0c;自然也是想使用opencv的imshow方法来显示图像&#xff0c;但是在google Colab中不可以使用&#xff0c;所以寻找了一下变通的显示方法。 方法1&#xff1a;使用matplotlib 使用plt需要交换一下r、b通道&#xff0c;否则显示不正常…

第十九章 UML

统一建模语言(Unified Modeling Language&#xff0c; UML )是一种为面向对象系统的产品进行说明、可视化和编制文档的一种标准语言&#xff0c;是非专利的第三代建模和规约语言。 UML 是面向对象设计的建模工具&#xff0c;独立于任何具体程序设计语言。 一、简介 UML 作为一…

正大国际:做qi货靠运气多点还是靠自己学习到认知度?

一个人能赚到自己认知范围以外的钱靠的是运气&#xff0c;能赚到自己认知范围内的钱靠的是能力。期货市场试错成本较高&#xff0c;交易自己熟悉和擅长的领域会大大降低失败概率。期货市场机会很多&#xff0c;陷阱也很多&#xff0c;如何坚持做认知范围内的决策是一个重要的交…

docker部署开源软件的国内镜像站点

下载镜像 docker pull registry.cn-beijing.aliyuncs.com/wuxingge123/le_monitor:latestdocker-compose部署 vim docker-compose.yml version: 3 services:le_monitor:container_name: le_monitorimage: registry.cn-beijing.aliyuncs.com/wuxingge123/le_monitor:latestpo…

算法——距离计算

距离计算常用的算法包括欧氏距离、曼哈顿距离、切比雪夫距离、闵可夫斯基距离、余弦相似度等。这些算法在数据挖掘、机器学习和模式识别等领域中被广泛应用。 1.欧氏距离 欧式距离也称欧几里得距离&#xff0c;是最常见的距离度量&#xff0c;衡量的是多维空间中两个点之间的…

心里健康(健康与生存)

你还认为 健康 是有个强壮的身体吗&#xff1f; 这样 肯定是错的 我们来说说 什么是健康与现代健康观 以及影响健康的因素 有哪些&#xff1f; 以及 健康对个人与社会的意义 首先 我们来看看 健康演变过程 公元 1000 年 Health 首次出现 它代表了 强壮 健全 完整等含义 健康 …

十四.PyEcharts基础学习

目录 1-PyEcharts介绍 优点&#xff1a; 安装: 官方文档&#xff1a; 2-PyEcharts快速入门 2.1 第一个图表绘制 2.2 链式调用 2.3 opeions配置项 2.4 渲染图片文件 2.5 使用主题 3-PyEcharts配置项 3.1 初始化配置项InitOpts InitOpts 3.2 全局配置项set_global_o…

京东云明修“价格战”,暗渡“政企云”

文&#xff5c;白 鸽 编&#xff5c;王一粟 云计算行业越来越“卷”&#xff0c;一边卷大模型&#xff0c;一边卷价格。 2024 刚一开年&#xff0c;阿里云就宣布百余款产品大降价&#xff0c;最高降幅达55%。在阿里云宣布降价后&#xff0c;京东云紧随其后宣布&#xff0…

80C51实现四种流水灯流水灯 | 自用学习笔记

单个流水灯 #include <reg51.h> #include <intrins.h> // 包含移位库函数的头文件void delay(void) // 定义延时函数 {unsigned char i, j;for(i 0; i < 200; i) // 循环延时&#xff0c;延时约50msfor(j 0; j < 125; j); }void main(void){ unsigned ch…

AcWing刷题-游戏

游戏 DP l lambda: [int(x) for x in input().split()]n l()[0] w [0] while len(w) < n:w l()s [0] * (n 1) for i in range(1, n 1): s[i] s[i - 1] w[i]f [[0] * (n 1) for _ in range(n 1)]for i in range(1, n 1): f[i][i] w[i]for length in range(2, …