C++ -3- 类和对象(中) | (三)END

news2025/1/12 8:48:18

文章目录

  • 6.日期类的实现
    • 构造函数
    • 赋值运算符 “=”
    • 前置++、后置++
    • 日期 - 日期
    • 日期类实现—代码汇总
    • 流插入
    • 流提取
  • 7.const成员
    • const 与 权限放大
  • 8.取地址及const取地址操作符重载


6.日期类的实现

#pragma once
#include <stdbool.h>
#include <iostream>
using namespace std;

class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month);

	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);

	// 拷贝构造函数
	// d2(d1)
	Date(const Date& d);

	// 赋值运算符重载
   // d2 = d3 -> d2.operator=(&d2, d3)
	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);
	
private:

	int _year;
	int _month;
	int _day;
};

构造函数

  • 需要检查一下日期是否非法
// 全缺省的构造函数
Date::Date(int year, int month, int day)
{
	if (day > GetMonthDay(year, month) || day < 0
		|| month < 0 || month > 12)//检查日期
	{
		cout << "日期非法" << endl;
	}
	else
	{
		_year = year;
		_month = month;
		_day = day;
	}
}

赋值运算符 “=”

  • 支持连续赋值,需要有返回值
Date& Date::operator=(const Date& d)
{
	if (*this == d)//如果时自己给自己赋值就不用进行下列操作了,直接返回即可
		return *this;
	_day = d._day;
	_month = d._month;
	_year = d._year;
	return *this;
}

前置++、后置++

  • 默认前置++Date& operator++()
  • 对于后置++:编译器加了一个参数,构成函数重载Date operator++(int),这里只能是int,这是一个规定

调用前置++和后置++实际上:

Date d1(2023,4,1);
++d1;  👉 d1.operator++();
d1++;  👉 d1.operator++(0);//编译器处理

这两个函数实现是 复用其他的操作符重载函数

// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

// 后置++
Date Date::operator++(int)
{
	Date tmp(*this);//调用拷贝构造
	*this += 1;
	return tmp;//调用拷贝构造,实际上返回的是tmp的一份临时拷贝
}

ps.自定义类型,建议尽量选择用前置++/ - -,效率更高

日期 - 日期

在不考虑的效率的情况下,采用计数的方式计算两个日期之间相差的天数。

计数:让小(早)日期不断++,直到等于大(晚)日期,加了多少次,就相隔多少天,注意:this指针指向左操作数

// 日期-日期 返回天数
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 count = 0;
	while (max != min)
	{
		++min;
		++count;
	}

	return count * flag;
}

日期类实现—代码汇总

#include "Date.h"

// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{
	int array[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if (month == 2)
	{
		if ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)))
		{
			++array[2];
		}
		return array[2];
	}
	else
	{
		return array[month];
	}
}

// 全缺省的构造函数
Date::Date(int year, int month, int day)
{
	if (day > GetMonthDay(year, month) || day < 0
		|| month < 0 || month > 12)
	{
		cout << "日期非法" << endl;
	}
	else
	{
		_year = year;
		_month = month;
		_day = day;
	}
}

// 拷贝构造函数
// d2(d1)
Date::Date(const Date& d)
{
	_day = d._day;
	_month = d._month;
	_year = d._year;
}

// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
	if (*this == d)
		return *this;
	_day = d._day;
	_month = d._month;
	_year = d._year;
	return *this;
}

// 析构函数
Date::~Date()
{
	_day = _month = _day = 0;
}

// 日期+=天数
Date& Date::operator+=(int day)
{
	if (day < 0)
		return *this -= (-1 * day);
	_day += day;
	int MonthDay = GetMonthDay(_year, _month);
	while (_day > MonthDay)
	{
		_day -= MonthDay;
		++_month;
		if (_month > 12)
		{
			++_year;
			_month = 1;
		}
		MonthDay = GetMonthDay(_year, _month);
	}

	return *this;
}

// 日期+天数
Date Date::operator+(int day)
{
	Date tmp(*this);

	return tmp += day;
}

// 日期-=天数
Date& Date::operator-=(int day)
{
	_day -= day;
	int MonthDay = GetMonthDay(_year, _month);
	while (_day < 0)
	{
		--_month;
		if (_month < 0)
		{
			--_year;
			_month = 12;
		}
		MonthDay = GetMonthDay(_year, _month);
		_day += MonthDay;
	}
	return *this;
}

// 日期-天数
Date Date::operator-(int day)
{
	Date tmp(*this);

	return tmp -= day;
}


// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

// 后置++
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;
}

// 前置--
Date& Date::operator--()
{
	*this -= 1;

	return *this;
}

// 后置--
Date Date::operator--(int)
{
	Date tmp(*this);
	*this -= 1;
	return tmp;
}

// >运算符重载
bool Date::operator>(const Date& d)
{
	if (_year < d._year)
		return false;
	if (_year > d._year)
		return true;
	if (_month < d._month)
		return false;
	if (_month > d._month)
		return true;
	if (_day < d._day)
		return false;
	if (_day > d._day)
		return true;

	return false;
}

// ==运算符重载
bool Date::operator==(const Date& d)
{
	return _day == d._day
		&& _month == d._month
		&& _year == d._year;
}

// >=运算符重载
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 || *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 count = 0;
	while (max != min)
	{
		++min;
		++count;
	}

	return count * flag;
}

流插入

在这里插入图片描述
iostream 为 Input/Output Stream 的缩写,即是输入/输出流。「流」是一连串从I/O设备读写的字符。

cout:Object of class ostreamcoutostream类的对象)
理解为:

class ostream
{
	void operator<<()
	{……}
}
ostream cout;

所以:

int i = 1;
cout << i;👉cout.operator<<(i);
  • cout是如何自动识别类型的?👇函数重载(下图,函数名相同,参数类型不同构成函数重载)
    在这里插入图片描述
    cout运算符重载+函数重载
  • 在日期类中实现一个流插入操作符重载
//函数定义:
void Date::operator<<(ostream& out)
{
	out << _year << "/" << _month << "/" << _day << endl;
}

//函数调用
void TestDate8()
{
	Date d1(2023, 4, 19);
	d1 << cout; 👉 d1.operator<<(cout);
}

int main()
{
	TestDate8();
	return 0;
}

分析:上述函数定义中的out 只是一个ostream类的实例化对象的“别名”可以随便取。

调用函数的过程中,隐含的参数 this指针传输Date类的对象→d1,作为左操作数ostream类的对象作为 操作符 << 的右操作数
由此,函数调用写作:d1 << cout;

  • 这个函数调用的写法很别扭,如何改变?
    →不作成员函数,作全局函数
    • 但是,作全局函数,Date类的成员变量是 private 无法访问
      →1. 写 Getyear……成员函数 获取 类的成员变量(Java常用)
      →2.友元函数(C++常用)

class Date中声明:

class Date
{
public:
//流插入
	friend void operator<<(ostream& out, const Date& d);
private:
	int _year;
	int _month;
	int _day;
};

函数定义:

//流插入
void operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
}

//函数调用:
cout << d1; 👉 operator<<(cout,d1);
  • 另外,<< 可以连续插入:(如下代码)→所以该函数需要有返回值
int i = 0, j = 1;
cout << i << j <<endl;
friend ostream& operator<<(ostream& out, const Date& d);//在类中声明

ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}

Date d1(2023, 4, 19);
Date d2(2022, 2, 2);
cout << d1 << d2;

在这里插入图片描述

  • C++ 为什么要用运算符重载输出?👉printf 无法打印自定义类型

流提取

和流插入类似

//流提取
istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

7.const成员

const 与 权限放大

在这里插入图片描述

将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

void Print() const
{
	cout << _year << "/" << _month << "/" << _day << endl;
}
  • const对象不可以调用非const成员函数 → “权限放大
  • 非const对象可以调用const成员函数 → “权限缩小

8.取地址及const取地址操作符重载

class Date
{ 
public :
	Date* operator&()
 	{
 		return this ;
  	}
 	const Date* operator&()const
 	{
 		return this ;
 	}
private :
	int _year ; // 年
	int _month ; // 月
	int _day ; // 日
};

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需
要重载,比如想让别人获取到指定的内容。


END

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

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

相关文章

vue vue-json-viewer 展示 JSON 格式数据

1、下载 vue-json-viewer npm 下载 vue-json-viewer &#xff1a; // Vue2 npm install vue-json-viewer2 --save // Vue3 npm install vue-json-viewer3 --saveyarn 下载 vue-json-viewer &#xff1a; // Vue2 yarn add vue-json-viewer2 // Vue3 yarn add vue-json-view…

基于LS1028 TSN 交换机软件系统设计与实现(三)

NXP 推出 OpenIL 作为用于工业领域的 Linux 发行版&#xff0c; OpenIL 新增的部分中 含有&#xff1a;支持实时的操作系统的扩展和支持工业厂房中自动化 OEM 的 Time-Sensitive 网络。 OpenIL 作为开放型的工业 Linux 系统最大的优势便是将实时计算在网络中 的…

JavaWeb——UDP的报文结构和注意事项

目录 一、UDP特点 1、无连接 2、不可靠 3、面向数据报 4、全双工通信 二、UDP报文结构 1、报头 2、载荷 三、端口 四、报文长度 五、校验和 1、定义 六、注意事项 1、UDP只有接收缓冲区、没有发送缓冲区 2、UDP大小受限 3、基于UDP的应用层协议 4、MTU对UDP协议…

《Java8实战》第11章 用 Optional 取代 null

11.1 如何为缺失的值建模 public String getCarInsuranceName(Person person) { return person.getCar().getInsurance().getName(); } 上面的这种代码就很容易出现NullPointerException的异常。 11.1.1 采用防御式检查减少 NullPointerException 为了避免NullPointerExce…

【Linux】基础IO——文件操作|文件描述符|重定向|缓冲区

文章目录 一、文件操作1. 文件预备知识2. 回顾C文件操作3. 文件操作的系统调用标志位的传递openwriteread 二、文件描述符1. 文件描述符的理解2. 文件描述符的分配规则 三、重定向1. 重定向的本质2. dup2系统调用 四、缓冲区1. 缓冲区的刷新策略2. 缓冲区的位置3. 简单模拟实现…

当程序员的好处和坏处,我用七年经历来和大家聊一聊

我想和大家分享一下我做程序员这七年来的一些感受和经验&#xff0c;同时也想和大家聊一聊做程序员的好处和坏处&#xff0c;让大家真正深入了解程序员的工作&#xff0c;是不是和大家想象中的一样。 首先&#xff0c;我毕业于四川某不知名的二本院校&#xff0c;于2016年进入…

【软考备战·希赛网每日一练】2023年4月19日

文章目录 一、今日成绩二、错题总结第一题第二题第三题 三、知识查缺 题目及解析来源&#xff1a;2023年04月19日软件设计师每日一练 一、今日成绩 二、错题总结 第一题 解析&#xff1a; 第二题 解析&#xff1a; server-side n.服务器端 enterprise n.企业 client n.客户 d…

matplotlib的配色(随机颜色函数,各种渐变色,彩虹色)

也是画图的时候经常会遇到的问题&#xff0c;什么颜色好看&#xff1f; 先直接上一个配色表&#xff1a; plt官网&#xff1a;List of named colors — Matplotlib 3.8.0.dev898g4f5b5741ce documentation 需要什么颜色传入就行了。 例如我下面画一个柱状图&#xff0c;自己选…

ctfhub技能树 web sql注入

1.整型注入 页面正常时 判断注入字段数 ?id1 order by 2判断注入回显位 ?id-1 union select 1,2查数据库 ?id-1 union select 1,database()库名&#xff1a;sqli 查数据表 ?id-1 union select 1,group_concat(table_name) from information_schema.tables where tabl…

kotlin协程、线程切换,函数方法委托

kotlin协程、线程切换&#xff0c;函数方法委托 一般编程的技法&#xff0c;比如&#xff0c;在Android中&#xff0c;假设在主线程中实现了一个函数&#xff0c;但该函数是耗时操作&#xff0c;毫无疑问&#xff0c;需要将这个函数的实现切入非主线程中操作&#xff0c;那么可…

Springcloud核心组件

在这里总结一下所有组件&#xff1a; springcloud是分布式微服务的一站式解决方案&#xff0c;可以说微服务是一个概念&#xff0c;而springcloud就是这个的实现 springcloud有五大核心组件&#xff1a; 注册中心 引言 由于微服务处于不同的进程&#xff0c;也就是说&…

【软考备战·希赛网每日一练】2023年4月13日

文章目录 一、今日成绩二、错题总结第一题第二题第三题第四题第五题 三、知识查缺 题目及解析来源&#xff1a;2023年04月13日软件设计师每日一练 一、今日成绩 二、错题总结 第一题 解析&#xff1a; 本题有争议&#xff0c;了解即可。 第二题 解析&#xff1a; 上图UML图为…

[计算机图形学]几何:网格处理(前瞻预习/复习回顾)

一、前言 网格的三种处理&#xff1a;网格细分&#xff0c;网格简化&#xff0c;网格正则化&#xff0c;细分会产生更多的三角面片来让模型更加光滑&#xff0c;简化则相反会减少网格的三角面片数量&#xff0c;正则化则会让三角形面更加规则。如上图中最右边两幅图&#xff0…

SpringBoot监听器源码解析

1.1 创建SpringApplication对象 public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args); }SpringApplication(。。){//获取到所有配置的ApplicationListener类型的监…

Android中的多线程编程与异步处理

Android中的多线程编程与异步处理 引言 在移动应用开发中&#xff0c;用户体验是至关重要的。一个流畅、高效的应用能够吸引用户并提升用户满意度。然而&#xff0c;移动应用面临着处理复杂业务逻辑、响应用户输入、处理网络请求等多个任务的挑战。为了确保应用的性能和用户体验…

《springboot实战》第六章 实现自定义全局异常处理

前言 springboot实现自定义全局异常处理&#xff0c;以及统一返回数据。 1、分析 首先&#xff0c;实现全局异常的流程 从图中可以看到&#xff0c;实现全局异常会需要这样几个类&#xff1a; 自定义异常接口类自定义异常枚举类自定义异常类自定义异常处理类自定义全局响应…

藏在GPT背后的治理分歧:那些赞同和反对的人们|AI百态(下篇)

AGI的火种正在燎原。 一面是无可否认的AI生产力&#xff0c;正在赋能千行百业&#xff1b;而另一面&#xff0c;这团火似乎烧向了我们不可控的隐秘角落。 在《AI百态&#xff08;上篇&#xff09;——ChatGPT的“N宗罪”》中&#xff0c;我们提到监管重锤在落下&#xff0c;意大…

安装 Docker和基本操作实验文档

一、安装 Docker 目前 Docker 只能支持 64 位系统。 systemctl stop firewalld.service setenforce 0 #安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2 yum-utils&#xff1a;提供了 yum-config-manager 工具。device mapper&#xff1a; 是Li…

分布式系统概念和设计-操作系统中的支持和设计

分布式系统概念和设计 操作系统支持 中间件和底层操作系统的关系&#xff0c;操作系统如何满足中间件需求。 中间件需求:访问物理资源的效率和健壮性&#xff0c;多种资源管理策略的灵活性。 任何一个操作系统的目标都是提供一个在物理层&#xff08;处理器&#xff0c;内存&a…

【网络安全】Xss漏洞

xss漏洞 xss漏洞介绍危害防御方法xss测试语句xss攻击语句1. 反射性xss2.存储型xss3.DOM型xssdvwa靶场各等级渗透方法xss反射型&#xff08;存储型方法一致&#xff09;LowMediumHightimpossible Dom型LowMediumHight xss漏洞介绍 定义&#xff1a;XSS 攻击全称跨站脚本攻击&am…