日期类完善

news2024/11/26 5:59:43

目录

日期类:

运算符重载:

​编辑

 赋值重载:

拷贝构造和赋值重载的区别:

 实现赋值重载:

划分成员函数:

日期类的声明和定义分离

日期类-=:

 日期类-

 前置后置++


日期类:

写一个简单的日期类:

#pragma once;
class Date
{
public:
	Date(int year=1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
#include<iostream>
using namespace std;
#include"Date.h"

void TestDate()
{
	Date d1;
	Date d2(2022, 9, 18);
	Date d3(2022, 2, 30);
	Date d4(2022, 2, 49);
	d3.Print();
	d4.Print();
}
int main()
{
	TestDate();
	return 0;
}

我们发现,日期d3和d4都不合法,我们进行运行:

也没有提示我们输入日期错误。

 我们可以对我们的构造函数进行优化:

Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
		if (!(year >= 1 && month >= 1 && month <= 12 && day >= 1 && day <= GetMonthDay(year, month)))
		{
			cout << "非法日期" << endl;
		}
	}

日期类的拷贝构造:

对于日期类,我们不需要写对应的拷贝构造,因为对于内置类型,编译器会默认执行值拷贝:

void TestDate()
{
	Date d1;
	Date d2(2022, 9, 18);
	/*Date d3(2022, 2, 30);
	Date d4(2022, 2, 49);
	d3.Print();
	d4.Print();*/
	Date d5(d2);
	d5.Print();
}
int main()
{
	TestDate();
	return 0;
}

运算符重载:

 赋值重载:

void TestDate()
{
	Date d1;
	Date d2(2022, 9, 18);
	/*Date d3(2022, 2, 30);
	Date d4(2022, 2, 49);
	d3.Print();
	d4.Print();*/
	/*Date d5(d2);
	d5.Print();*/
	Date d5;
	d5 = d2;
}

拷贝构造和赋值重载的区别:

拷贝构造:一个对象拷贝初始化另一个要创建的对象。

赋值重载:已经存在的两个对象之间的拷贝。 

 实现赋值重载:

赋值重载可以传值传参吗?

可以,不会发生无穷递归,发生无穷递归的条件是: 拷贝构造时,使用传值传参,传值传参本身就是拷贝构造,拷贝构造又需要传值传参,无限循环。

所以这里可以传值传参。

但是传值传参还需要调用拷贝构造,有些麻烦,我们最好还是使用传地址传参。

void operator=(const Date&d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
void TestDate()
{
	Date d1(2022, 9, 10);
	Date d2;
	d2 = d1;
}
int main()
{
	TestDate();
	return 0;
}

我们进行测试:

赋值成功。

赋值重载写的不够全面,我们知道整型可以连等:

int main()
{
	/*TestDate();*/
	int i, j;
	i = j = 1;
	return 0;
}

我们这里是不能连等的:

void TestDate()
{
	Date d1(2022, 9, 10);
	Date d2, d3;
	d2.Print();
	d3=d2 = d1;
	d2.Print();
}
int main()
{
	TestDate();
	/*int i, j;
	i = j = 1;*/
	return 0;
}

原因如下:

 

 

这里我们把d1赋值给d2之后,返回值应该是d2,但是我们实现的函数是没有返回值的,所以我们需要完善返回值:

Date operator=(const Date&d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}

传值传参是拷贝构造,传值返回也是拷贝构造,所以我们这里可以用传引用返回:

而且this指向的对象出了作用域依旧存在,我们可以用引用返回。

能不能不返回*this,返回d呢?

答:不可以

Date& operator=(const Date&d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return d;
	}

1:因为d是只读的,传引用返回后的类型变成可读可写的了,属于权限的放大。

2:赋值的返回值是左操作数,不能返回右操作数。

划分成员函数:

赋值运算符的重载对于内置类型完成值拷贝,所以对于日期类,我们可以不定义赋值重载

 

我们没有定义赋值重载函数,依旧可以完成日期类对象的赋值。

大部分类的默认赋值重载都不需要我们自定义,但是有些需要,例如栈:

#pragma once;
class Stack
{
public:
	Stack(int capacity=4 )
	{
		_a = (int*)malloc(sizeof(int)*capacity);
		if (_a == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		_top = 0;
		_capacity = capacity;
		cout << "Stack构造函数()" << endl;
	}
	Stack(const Stack&st)
	{
		_a=(int*)malloc(sizeof(int)*st._capacity);
		if (_a == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		memcpy(_a, st._a, sizeof(int)*st._top);
		_top = st._top;
		_capacity = st._capacity;
	}
	void Push(int x)
	{
		_a[_top++] = x;
	}
	~Stack()
	{
		free(_a);
		_a = nullptr;
		_top = _capacity = 0;
		cout << "Stack析构函数()" << endl; 
	}
private:
	int*_a;
	int _capacity;
	int _top;
};

我们没有实现赋值重载,看看能否使用赋值重载

void StackTest()
{
	Stack st1;
	st1.Push(1);
	st1.Push(2);

	Stack st2;
	st2.Push(10);
	st2.Push(20);
	st2.Push(30);
	st2.Push(40);
	st1 = st2;
}
int main()
{
	StackTest();
	/*int i, j;
	i = j = 1;*/
	return 0;
}

运行之后,直接报错。

 

我们进行值拷贝:

把st2._top赋值给st1._top,把st2._capacity赋值给st1._capacity。

再让st1._a指向st2._a的位置。

后创建st2的先析构,析构之后st2所指向的空间的数据释放了,这时候st1再进行析构就导致了越界访问。

并且原本属于st1的指向的数据的地址也找不到了,造成了内存泄漏。

所以对于栈类,我们要自己实现赋值重载:

 

我们先释放掉st1所指向的空间的数据,然后新创建一个空间,拷贝st2的数据,让st1指向该空间:

 

Stack& operator=(const Stack&st)
	{
		free(_a);
		_a = (int*)malloc(sizeof(int)*st._capacity);
		if (_a == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		memcpy(_a, st._a, sizeof(int)*st._top);
		_top = st._top;
		_capacity = st._capacity;
		return *this;
	}

 

完成了深拷贝。 

还有一种情况:

用自己去赋值自己。

 

我们进行运行,发现数据出现了错误。

 因为

 我们可以先提前判断:

Stack& operator=(const Stack&st)
	{
		if (&st != this)
		{
			free(_a);
			_a = (int*)malloc(sizeof(int)*st._capacity);
			if (_a == nullptr)
			{
				perror("malloc fail");
				exit(-1);
			}
			memcpy(_a, st._a, sizeof(int)*st._top);
			_top = st._top;
			_capacity = st._capacity;
		}
		return *this;
	}

对于一些有资源释放的类,我们也可以不自己写:

class MyQueue
{
public:
	void push(int x)
	{
		_pushST.Push(x);
	}
private:
	Stack _pushST;
	Stack _popST;
	size_t size = 0;
};

对于内置类型完成值拷贝,对于自定义类型,调用其默认赋值重载。

void MyQueueTest()
{
	MyQueue s1;
	s1.push(10);
	MyQueue s2;
	s2 = s1;
}
int main()
{
	MyQueueTest();
	/*int i, j;
	i = j = 1;*/
	return 0;
}

完成了深拷贝。 

日期类的声明和定义分离

对于比较小并且频繁调用的函数,这类函数一般是内联函数,内联函数只能在类里面定义,不能声明和定义分离。

对于行数不多并且调用不频繁的我们可以声明和定义分离。

日期类-=:

Date&Date::operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month == 0)
		{
			_year--;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}
#include"Date.h"
void TestDate1()
{
	Date d1(2022, 10, 19);
	d1 -= 1000;
	d1.Print();
}
int main()
{
	TestDate1();
	return 0;
}

 日期类-

Date Date::operator-(int day)
{
	Date ret(*this);
	ret -=day;
	return ret;
}
#include"Date.h"
void TestDate1()
{
	Date d1(2022, 10, 19);
	Date d2 = d1 - 10000;
	d2.Print();
}
int main()
{
	TestDate1();
	return 0;
}

假如我们要减去一个负数呢?

#include"Date.h"
void TestDate1()
{
	Date d1(2022, 10, 19);
	
	d1 -= -10000;
	d1.Print();
}
int main()
{
	TestDate1();
	return 0;
}

 前置后置++

 

我们在定义的时候如何区分前置和后置++?

 

Date& Date::operator++()
{
	*this += 1;
	return *this;
}
Date Date::operator++(int)
{
	Date ret = *this;
	*this + 1;
	return ret;
}

 

 

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

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

相关文章

获取一个对象的直接接口和间接接口

package com.ljr;import java.util.*;public class InterfaceUtils {public static List<Class<?>> getInterfaces(Object obj) {List<Class<?>> interfaces new ArrayList<>();Class<?> clazz obj.getClass();while (clazz ! null) …

(09_13)杭州站|阿里云 Serverless 技术实践营(Serverless + 大数据)开启报名!

活动简介 “Serverless 技术实战与创新沙龙 ” 是一场以 Serverless 为主题的开发者活动&#xff0c;通过一个下午的时间增进对 Serverless 技术的理解&#xff0c;快速上手,活动受众以关注 Serverless 技术的开发者、企业决策人、云原生领域创业者为主&#xff0c;活动形式为…

肖sir__mysql之子查询语句__006

一、子查询 定义:一个查询嵌套另一个查询 例如&#xff1a; 题目&#xff1a;财务部门的收入总和&#xff1b; dept&#xff1a;财务部门 incoming&#xff1a;工资 &#xff08;1&#xff09;先将一个结果查询出来&#xff1a;财务部门的编号查询出来 select dept1 from dept …

管理类联考——数学——汇总篇——知识点突破——代数——等差数列

⛲️ 一、考点讲解 1.定义 如果在数列{ a n a_n an​}中&#xff0c; a n 1 − a n d a_{n1}-a_nd an1​−an​d&#xff08;常数&#xff09; &#xff08; n ∈ N &#xff0b; &#xff09; &#xff08;n∈N_&#xff0b;&#xff09; &#xff08;n∈N&#xff0b;​&a…

一文详解融资融券操作方法和交易规则!

融资融券是投资者利用券商提供的资金或证券进行交易的一种加杠杆的金融操作方式。通过融资融券&#xff0c;投资者可以利用杠杆效应扩大自己的投资规模&#xff0c;提高投资回报。现在有很多投资者使用融资融券账户加杠杆操作&#xff0c;但很多朋友开通了融资融券却也不太会操…

《计算机视觉中的多视图几何》笔记(3)

3 Projective Geometry and Transformations of 3D 这章主要讲的是3D的射影几何&#xff0c;与2D的射影几何差不多。主要区别是&#xff1a; 3D射影几何对偶的是点和平面&#xff0c;直线是自对偶的。3D空间中直线有4个自由度&#xff0c;这一现象并不是那么容易直接得出。一…

DHCP与静态IP:哪种适合你的网络需求?

​如今&#xff0c;大多数网络设备&#xff08;如路由器或网络交换机&#xff09;都使用IP协议作为通过网络进行通信的标准。在IP协议中&#xff0c;网络上的每个设备都有一个唯一的标识符&#xff0c;称为IP地址。实现这一点的最简单方法是配置固定IP地址或静态IP地址。由于静…

Hyperopt:分布式异步超参数优化(Distributed Asynchronous Hyperparameter Optimization)

1、概述 在深度学习的训练模型过程中&#xff0c;参数的优化是一个比较繁琐的过程&#xff0c;一般使用网格搜索Grid search与人工搜索Manual search&#xff0c;所以这个参数优化有时候看起来就像太上老君炼丹&#xff0c;是一个有点玄的东西。 那有没有一种可以自动去调优的…

c\c++ windows自动打开cmd并进入mysql

每次不用可视化工具查看数据库的时候饭都要winr->cmd->mysql -u root -p->密码 虽然不麻烦但是多少也得消耗你几秒钟&#xff0c;秉承着时间就是金钱的观念 我决定通过windows模拟输入实现快速通过命令行查看mysql数据库 涉及到的知识: windows拉起进程&#xff0c;…

无线耳机能不能设计成我想象的这样的?

市面上有没有这种耳钉式的无线耳机啊&#xff0c;有的话能推荐一下吗&#xff1f;没有的话无线耳机的厂家能不能考虑一下这个方案&#xff0c;这样我们女生带耳机穿衣服或者梳头发的时候就不用摘下来了&#xff0c;也不会经常到处找耳机了 这样既能当耳机&#xff0c;又能做装…

测试 c++ 之 is_function_v

如图&#xff0c;给 is_function_v 传入一个类&#xff0c;为假&#xff0c;传入一个函数对象则为真 。 &#xff08;2&#xff09;以下是文心一言的解释&#xff0c;真好&#xff1a; 在 C 中&#xff0c;std::is_function_v 是一个类型特征&#xff08;type trait&#xff09…

数组和指针笔试题解析之【数组】

前言&#xff1a; 1.数组名的意义&#xff1a; sizeof(数组名)&#xff1a;这里的数组名表示整个数组&#xff0c;计算的是整个数组的大小&#xff0c;单位是字节。&数组名&#xff1a;这里的数组名表示整个数组&#xff0c;取出的是整个数组的地址。除此之外所有的数组名都…

爬虫逆向实战(33)-某联社数据(webpack)

一、数据接口分析 主页地址&#xff1a;某联社 1、抓包 通过抓包可以发现数据接口是/nodeapi/telegraphList 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现有一个sign加密参数 请求头是否加密&#xff1f; 无 响应是否加密&#x…

uni-app 新增 微信小程序之新版隐私协议

一、manifest.json中配置 "__usePrivacyCheck__": true 二、编写封装后的组件 <template><view class"privacy" v-if"showPrivacy"><view class"content"><view class"title">隐私保护指引</…

无涯教程-JavaScript - SHEET函数

描述 SHEET函数返回参考图纸的图纸编号。 语法 SHEET (value)争论 Argument描述Required/OptionalValue 值是您要为其指定工作表编号的工作表名称或参考。 如果省略value,则SHEET返回包含该功能的工作表的编号。 Optional Notes 除了所有其他工作表类型(宏,图表或对话框工…

【Python爬虫】python打印本地代理

目录 前言 代理 IP 的使用 1. 获取代理 IP 2. 选择合适的代理 IP 3. 设置代理 IP 4. 验证代理 IP 代码案例 总结 前言 在进行网络爬虫时&#xff0c;使用代理是非常重要的。因为爬虫经常会被网站封 IP&#xff0c;而代理可以隐藏你的真实 IP 地址&#xff0c;让你可以…

智慧港口4G+UWB+GPS/北斗RTK人员定位系统解决方案

港口人员定位系统能够帮助企业实现对港口作业人员的全面监控和管理&#xff0c;不仅可以保障人员的人身安全&#xff0c;还可以提高人员的作业效率&#xff0c;为港口的可持续发展提供有力保障。接下来为大家分享智慧港口人员定位系统解决方案。 方案背景 1、港口作业人员多&a…

APK安装过程解析

应用端发起安装APK的代码一般如下&#xff1a; Intent installintent new Intent();installintent.setAction(Intent.ACTION_VIEW);installintent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);installintent.setDataAndType(xxx,"application/vnd.android.package-archive&…

SpringMVC系列(四)之SpringMVC实现文件上传和下载

目录 前言 一. SpringMVC文件上传 1. 配置多功能视图解析器 2. 前端代码中&#xff0c;将表单标记为多功能表单 3. 后端利用MultipartFile 接口&#xff0c;接收前端传递到后台的文件 4. 文件上传示例 1. 相关依赖&#xff1a; 2. 逆向生成对应的类 3. 后端代码&#xf…

DC电源模块在保护设备损坏的重要功能

BOSHIDA DC电源模块在保护设备损坏的重要功能 DC电源模块是一种电源管理设备&#xff0c;用于将交流电转换为直流电并提供给设备供电。它通常由多个电子元件组成&#xff0c;包括整流器、滤波器、稳压器等&#xff0c;以确保电源输出稳定&#xff0c;满足设备的电源需求。 在…