从零开始的C++生活——第二讲——03

这一讲主要实现以下类和对象的一个实例------日期类,会用到之前讲过的类的知识。

在介绍这个之前,我需要先补充一点关于前置++后置++前置--后置--的运算符重载、以及cincout的运算符重载。

首先是++--,当运算符重载的时候,假如你写成成员变量,那么默认this指针指向的对象就是第一个操作数,对于++--这种一元运算符来说,我们是不用再传其他参数的。

但是由于C++规定的默认参数顺序问题,这里没办法对前置++后置++区分,甚至你连重载都做不到,因为不论前置后置,++都是一样的,你的函数名只能是operator++,参数只能是this,只有返回值时可能不同的,但是返回值相同与否和重载没什么关系,为了解决上述问题,C++规定,后置++需要传一个int形参,以作区分。--也是类似。

下面是cin,cout其实也就是<< >>流插入流提取运算符的重载,二元运算符,对于<<来说,ostream其实也就是cout是第一个操作数,我们要打印的对象,也就是this指针(其实这么说不准确)就是第二个操作数,你发现异常了没有?当我们重载操作符到成员函数时,this必须是第一个操作数,假如我们写成成员函数,那就变成了*this << out,这也太奇怪了,所以我们把这两个写成全局函数,就可以解决这个问题。

值得注意的是,当我们调用<<运算符时,需要支持链式调用,即cout << a <<b;意味着打印完a之后,接着还需要ostream&对象也就是cout接着作为<<第一个操作数打印b,所以我们需要返回值,>>同理。

还有一点需要注意,当我们写成全局函数的时候,是不能调用默认为private的成员变量的,那时候就要在类中将这两个重载运算符函数置为友好函数,也就是函数声明前加上friend。

接下来展示一下Date代码

Date.h

cpp 复制代码
#pragma once

#include <iostream>
using namespace std;

class Date
{

	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, const Date& d);
public:
	bool CheckDate() const;
	// 获取某年某月的天数 
	int GetMonthDay(int year, int month) const;
	// 全缺省的构造函数
	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);
	void print()
	{
		cout << _year << '/' << _month << '/' << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

Date.cpp

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include "Date.h"



// 获取某年某月的天数
int Date::GetMonthDay(int year, int month) const
{
	static int m_day[13] = { -1,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 m_day[month] + 1;
	}
	return m_day[month];
}

// 全缺省的构造函数
Date::Date(int year , int month , int day )
{
	_year = year;
	_month = month;
	_day = day;
	
}
//// 拷贝构造函数
//	// d2(d1)
//Date::Date(const Date& d)
//{
//	_year = d._year;
//	_month = d._month;
//	_day = d._day;
//}


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

// 日期+=天数
Date& Date::operator+=(int day)
{

	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month == 13)
		{
			_month = 1;
			_year++;
		}
	}
	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 == 13)
		{
			tmp._month = 1;
			tmp._year++;
		}
	}
	return tmp;*/
	tmp += day;
	return tmp;
}
// 日期-天数
Date Date::operator-(int day)
{
	Date tmp = *this;
	tmp._day -= day;
	while (tmp._day <= 0)
	{
		if (tmp._month == 1)
		{
			tmp._day += GetMonthDay(tmp._year, 12);

		}
		else
			tmp._day += GetMonthDay(tmp._year, tmp._month-1);
		tmp._month--;
		if (tmp._month == 0)
		{
			tmp._month = 12;
			tmp._year--;
		}
	}
	return tmp;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
	*this = *this - day;
	return *this;
}
// 前置++
Date& Date::operator++()
{
	_day++;
	if (_day > GetMonthDay(_year, _month))
	{
		_day = 1;
		_month++;
		if (_month == 13)
		{
			_month = 1;
			_year++;
		}
	}
	return *this;
}
// 后置++
Date Date::operator++(int)
{
	Date tmp = *this;
	++(*this);
	return tmp;
}


// 后置--
Date Date::operator--(int)
{
	Date tmp = *this;
	(this->_day)--;
	if (_day == 0)
	{
		if (_month == 1)
		{
			_day = GetMonthDay(_year, 12);
			_month = 12;
			_year--;
		}
		else
			_day = GetMonthDay(_year, _month - 1);
	}
	return tmp;

}
// 前置--
Date& Date::operator--()
{
	(*this)--;
	return *this;
}
// >运算符重载
bool Date::operator>(const Date& d)
{
	if (_year == d._year)
	{
		if (_month == d._month)
		{
			return _day > d._day;
		}
		else
			return _month > d._month;
	}
	return _year > d._year;
}
// ==运算符重载
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)
{
	//0 this 1 d
	int min = 0;
	if (*this > d)
	{
		min = 1;
	}
	int day = 0;
	Date lit;
	Date big;
	int flag = -1;
	if (min == 0)
	{
		lit = *this;
		big = d;
	}
	else
	{
		lit = d;
		big = *this;
		flag = 1;
	}
	while (lit != big)
	{
		++lit;
		day++;
	}
	return flag * day;
}

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

istream& operator>>(istream& in, const Date& d)
{
	while (1)
	{
		cout << "请依次输入年月日->";
		in >> d._year >> d._month >> d._day;
		if (!d.CheckDate())
		{
			cout << "日期非法" << endl;
		}
		else
		{
			break;
		}
	}
	
	return in;
}


bool Date::CheckDate() const 
{
	if (_month > 12 || _month < 1)
		return false;
	else if (_day != GetMonthDay(_year, _month))
		return false;
	else
		return true;
}

这个程序实现了日期的一些基本操作,比如加减天数,减去日期,自增自减,等等。

在最后,我来介绍一下最后一个需要跟大家讲的默认成员函数,即取地址运算符重载函数。

先来介绍以下const成员函数,我们上边其实已经用到了const成员函数,定义const成员函数的方式很简单,在函数声明、定义后加上const即可,默认我们的this指针是Date * const this,之前我们讲指针的时候也聊过,在*后加const,意味着不能修改this的指向,但不代表不能修改*this,那么这是否会造成安全隐患呢?比如我们简单写个+-运算符的重载函数,你却可以修改*this,这不太安全也不符合逻辑,而将成员函数修改为const成员函数后,参数就变成了const Date* const this,可以解决这个问题。

值得注意的是,const对象是不能调用普通成员函数的,这被视为是权限的放大,但是普通对像是可以调用const成员函数,权限缩小无所谓。

取地址运算符重载函数。

这个函数一般来讲是不用手动实现的,其实说是一个,其实是一种,取地址运算符重载成员函数也有const和非const两种,前者返回const对象,本身是const成员函数,后者则是普通,当程序中都有时,优先调用const,这其实没啥可讲的,因为你就是返回一个this就好了,this本身就是地址,除非你想瞎返回一个地址才需要手动实现。

相关推荐
布莱克6052 小时前
QtWidgets 与 QML:两大 UI 开发框架的全面对比
开发语言·c++·qt·ui·架构
老木避暑研究所2 小时前
如何定义一个可量化的“宜居指数”?——从云澜栖康养数据评估说起
生活
hetao17338372 小时前
2026-10-20 hetao1733837 的刷题记录
c++·算法
x10n94 小时前
微软 VC++ 运行库合集VCRedistPack
开发语言·c++·microsoft·vc++运行库·dll报错
qz_Serene4 小时前
C++:string(底层,常用接口,具体题目,模拟实现)
开发语言·c++
杜 硕4 小时前
从零开始的C++生活——第二讲——04
生活
king13598745504 小时前
LiteRT Tensor API:C++ 编写端侧模型图,XNNPACK、GPU 与 NPU 怎么选?
开发语言·c++·人工智能·chatgpt·架构·aigc
青少儿编程课堂5 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:差分数组与区间修改实战解析
c++·python·算法·bfs·信息学竞赛
纪念 2295 小时前
C++ list讲解
c++·windows·list