[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员

这篇具有很好参考价值的文章主要介绍了[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

 

目录

1、前言

2、全缺省的构造函数

3、打印接口

4、拷贝构造

5、赋值运算符重载(operator=)

5.1赋值重载是默认成员函数,重载格式:

5.2 赋值重载不能为全局函数

5.3 编译器默认生成

6、析构函数

7、operator>

8、operator==

9、operator>=

10、operator<

11、operator<=

12、operator!=

13、operator+= (日期+=天数)

14、operator+ (日期+天数)

15、operator-= (日期-=天数)

16、operator- (日期-天数)

17、前置++,后置++,前置--,后置--

18、日期 - 日期(返回天数)

19、const成员


1、前言

本篇文章我们将主要实现以下的这些接口:

#include <iostream>
using namespace std;

class Date
{
public:

	// 获取某年某月的天数
	int GetMonthDay(int year, int month) const;
	// 全缺省的构造函数
	Date(int year = 1900, int month = 1, int day = 1);
	//打印接口
	void Print() const;


	// 拷贝构造函数
	// d2(d1)
	Date(const Date& d);
	// 赋值运算符重载
	// d2 = d3 -> d2.operator=(&d2, d3)
	Date& operator=(const Date& d);
	// 析构函数
	~Date();


	//总结一下:只读函数可以加const,内部不涉及修改成员的都是只读函数
	// >运算符重载
	bool operator>(const Date& d) const;
	// ==运算符重载
	bool operator==(const Date& d) const;
	// >=运算符重载
	bool operator>=(const Date& d) const;
	// <运算符重载
	bool operator<(const Date& d) const;
	// <=运算符重载
	bool operator<=(const Date& d) const;
	// !=运算符重载
	bool operator!=(const Date& d) const;

	// 日期+=天数
	Date& operator+=(int day);
	// 日期+天数
	Date operator+(int day) const;
	// 日期-天数
	Date operator-(int day) const;
	// 日期-=天数
	Date& operator-=(int day);


	// 函数重载
	// 运算符重载
	// 前置++
	Date& operator++(); //++d1 -> d1.operator()
	// 加一个int参数,进行占位,跟前置++构成函数重载进行区分
	// 后置++
	Date operator++(int); //d1++ -> d1.operator(0)
	// 后置--
	Date operator--(int);
	// 前置--
	Date& operator--();


	// 日期-日期 返回天数
	int operator-(const Date& d) const;

private:

	int _year;
	int _month;
	int _day;

};

本次的项目我们以多文件来写,包含以下三个文件:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

接下来我们就对以上的接口一一进行实现:

2、全缺省的构造函数

对于全缺省的构造函数正常写的时候存在一个不足,万一传参传的月份与天是不存在的,虽然对实例化的对象初始化了,但是是违法的,因此我们需要判断一下,这里就需要我们对月份的天数写一个函数,构造的时候先对比一下。

我们这里先实现GetMonthDay接口:

// 获取某年某月的天数
int Date::GetMonthDay(int year, int month) const
{
	static int monthDay[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };

	if(2 == month
		&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
	{
		return 29;
	}

	return monthDay[month];
}
// 全缺省的构造函数
Date::Date(int year, int month, int day)
{
	if (month < 1 || month > 12
		|| day < 1 || day > GetMonthDay(year, month))// 判断日期是否合法
	{
		cout << "非法日期" << endl;
		exit(-1);
	}
	else
	{
		_year = year;
		_month = month;
		_day = day;
	}
}

对于GetMonthDay接口,我们写了一个数组存每个月有多少天,默认二月是28天,在下面我们会判断一下如果是找二月的天数,对年进行判断,看看是否为闰年,为闰年的时候直接返回29,其他的就直接返回月份对应的天数。我们对数组使用static修饰,因为后面会不断的调用此函数,因此我们将其放到静态区,只开辟一次,节省了时间,一次的时间不多,但是如果是大量的调用会极大的提升效率。

这里我们会有人问,为什么在GetMonthDay接口后面加一个const,这里我们来说明一下:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

3、打印接口

打印接口没什么讲的,我们直接一把梭哈:

//打印接口
void Date::Print() const
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

打印接口对this使用const修饰是因为,有可能我们传过来的对象是const修饰的,如果Print接口不加const就涉及权限放大的问题,导致出错。改为const后就不存在权限问题了。

4、拷贝构造

对于拷贝如果还有不清楚的可以点击后面的链接,里面有对拷贝构造详细讲解哦:点这里哦

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

5、赋值运算符重载(operator=)

5.1赋值重载是默认成员函数,重载格式:

参数类型:const T&,传引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否自己给自己赋值
返回*this:要复合连续赋值的含义

我们按重载格式来写一下:

// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
	if (this != &d)// 存在this就是d的情况
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	return *this;
}

5.2 赋值重载不能为全局函数

原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

我们自己写一下试试:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

我这里使用的vs2019编译器,编译器会提示,编译期间直接报错了,因此赋值运算符重载是不可以为全局函数的。

5.3 编译器默认生成

当我们不写的时候编译器会自动生成一个复制重载函数,但是默认生成的函数对内置类型是直接赋值的,对自定义类型的成员变量需要调用对应的类赋值重载函数来完成赋值。

因此,如果成员变量里存在自定义类型(类类型),自定义类型的赋值重载函数必须是正确的,这样才是对的。

如两个栈实现一个队列,队列的赋值重载函数可以默认生成,但是栈的必须自己写,因为栈存在申请资源,如果直接拷贝,两个栈使用的是同一块资源,这样的话,一个是出栈的栈,一个是进栈的栈,不管进出其实是对同一个栈进行操作,这就是错误的。

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。

赋值与拷贝的区别:拷贝是一个已经存在的对象去初始化另一个要创建的对象;

赋值是两个已经存在的对象进行拷贝。

6、析构函数

对于析构函数如果还有不清楚的可以点击后面的链接,里面有对析构函数详细讲解哦:点这里哦

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

7、operator>

对 日期>日期 的判断中

1、当年小于后,就不用再比了,直接返回false

2、当年相同比较月,月小于后,直接返回false

3、当年月都相同,日小于后,返回false

4、当以上判断都不正确,说明前面的日期 大于 后面的日期,返回true

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

8、operator==

对 日期==日期 的判断很简单,年月日分别都相等就是正确的,我们看看代码实现:

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

上面的代码还可以再精简一下:

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

9、operator>=

对于 >= 来说,我们其实可以复用上面的 >与== ,不用再去写一套逻辑来判断,>= 的逻辑就是大于或者等于。

我们来看看实现代码:

// >=运算符重载
bool Date::operator>=(const Date& d) const
{
	return (*this > d) || (*this == d);
}

10、operator<

< 与 >= 是相反的逻辑,因此我们对 >= 取反就可以实现。

// <运算符重载
bool Date::operator<(const Date& d) const
{
	return !(*this >= d);
}

11、operator<=

<= 与 > 是相反的逻辑,因此我们对 > 取反就可以实现。

// <=运算符重载
bool Date::operator<=(const Date& d) const
{
	return !(*this > d);
}

12、operator!=

!= 与 == 是相反的逻辑,因此我们对 == 取反就可以实现。

// !=运算符重载
bool Date::operator!=(const Date& d) const
{
	return !(*this == d);
}

13、operator+= (日期+=天数)

+=是在原基础上进行修改,因此隐含的this不能用const修饰,因为在原基础上修改,所以出了+=函数体,对象还在,我们使用引用返回,这样可以减少拷贝。

我们画图对 += 天数分析:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

代码实现:

// 日期+=天数
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= (-day);
	}

	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		//月进位
		_month++;

		//月满了
		if (13 == _month)
		{
			_year++;
			_month = 1;
		}
	}

	return *this;
}

我们来测试一下:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

对照看看我们写的+=是否正确

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

14、operator+ (日期+天数)

+与+= 的区别在于+=是对对象本身+,而+不是对对象本身的改变。所以我们需要实例化一个新的对象,将传来的对象拷贝给新的对象,存放+天数的结果并返回。

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

	tmp += day;

	return tmp;
}

这里我们拷贝了一份之后,就能复用+=的代码。

我们这里看看传的对象与+后的对象的结果:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

这里我们可以看到+并没有影响到d1的结果。

15、operator-= (日期-=天数)

-=是在原基础上进行修改,因此隐含的this不能用const修饰,因为在原基础上修改,所以出了-=函数体,对象还在,我们使用引用返回,这样可以减少拷贝。

我们画图对-=天数进行分析:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

代码实现:

// 日期-=天数
Date& Date::operator-=(int day)
{
	if (day < 0)
	{
		return *this += (-day);
	}

	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (0 == _month)
		{
			_year--;
			_month = 12;
		}

		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

运行结果:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

对比一下,看我们实现的是否正确:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

16、operator- (日期-天数)

-与+ 的逻辑是类似的,-与-= 的区别在于-=是对对象本身-,而-不是对对象本身的改变。所以我们需要实例化一个新的对象,将传来的对象拷贝给新的对象,存放-天数的结果并返回。

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

	tmp -= day;

	return tmp;
}

这里拷贝一份this之后,就可以在拷贝的tmp上复用-=。

我们来测试一下:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

17、前置++,后置++,前置--,后置--

对于前置++与后置++,前置--与后置--,它们的函数名是相同的,但是实现的功能是不同的,如果在符号表里找这怎么能分得清楚呢?

对于这样的问题,C++有自己确定的规定,C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递。后置--也是如此。

这样就能实现函数重载,符号表中函数名虽然相同,但是一个有参数一个没参数。

下面我们对这几个函数接口分别实现:

前置++的规则是:先++,再使用。因此前置++就相当于+=1,复用+=。

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

后置++的规则是:先使用,再++。这里我们先将this拷贝一份,然后对this+=1,返回拷贝的对象,这样就做到了先使用,再++。

// 后置++
Date Date::operator++(int) //d1++ -> d1.operator(0)
{
	Date tmp(*this);

	*this += 1;

	return tmp;
}

前置--的规则是:先--,再使用。因此前置++就相当于-=1,复用-=。

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

	return *this;
}

后置--的规则是:先使用,再--。这里我们先将this拷贝一份,然后对this-=1,返回拷贝的对象,这样就做到了先使用,再--。

// 后置--
Date Date::operator--(int)
{
	Date tmp(*this);

	*this -= 1;

	return tmp;
}

18、日期 - 日期(返回天数)

此接口是 日期-日期,这里有一个存在一个小细节,当 小日期-大日期 的时候,返回值就是负数,因此我们对这个细节要注意一点,我们来对这个接口的思路梳理一遍:

1、我们用假设法,假设this是大日期,将其赋值给max对象,第二个参数是小日期,将其赋值给min对象,并定义一个flag初始化为 1;

2、比较一下,如果this是小日期那么将max、min两个对象的内容重新赋值,并将flag赋值为 -1;

3、定义一个计数器 n,让小追大,++min一次,计数器也++,追上后就跳出循环,返回 n*flag 即可。

注意:我们让小追大的时候使用前置++,虽然前置++与后置++都可以实现,但是后置++的接口中需要拷贝两次,开始拷贝一次,返回值会再拷贝一次,前置++在大量计算的时候可以实现时间与空间双重优势。

我们来实现代码:

// 日期-日期 返回天数
int Date::operator-(const Date& d) const
{
	int flag = 1;
	Date max = *this;
	Date min = d;
	if (max < min)
	{
		max = d;
		min = *this;
		flag = -1;
	}

	int n = 0;
	while (min != max)
	{
		++n;
		++min;
	}

	return n * flag;
}

测试:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

19、const成员

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

这里我们使用 Print 接口来讲:

使用const修饰后,与原本的成员函数是不冲突的,因为是构成重载的。

我们来看看两种版本的 Print 接口:

void Date::Print()
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

void Date::Print() const
{
	cout << _year << "年" << _month << "月" << _day << "日" << endl;
}

对于打印函数来讲,函数内部是不涉及修改成员的,这种就是只读函数。

因此我们使用了const修饰,还存在一种问题,当我们的对象是const修饰,如果Print函数不用const修饰,在调用的时候就存在权限放大问题。

我们先将const修饰的Print函数频闭掉:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

我们再将const修饰的接口放开看看:

[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员,C++,c++,算法,开发语言

总结:相同函数,const修饰的this与不修饰的函数构成重载;

函数内部是不涉及修改成员的就是只读函数,const修饰后更安全,并且对于具有常属性的对象也可以兼容。文章来源地址https://www.toymoban.com/news/detail-640228.html

到了这里,关于[C++] 类与对象(中)完整讲述运算符重载示例 -- 日期类(Date) -- const成员的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++初阶】类与对象:6大默认成员函数------拷贝构造和赋值运算符重载

      拷贝构造函数: 只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰) ,在用已存在的类类型对象创建新对象时由编译器自动调用。 1. 拷贝构造函数是 构造函数的一个重载形式 ; 2. 拷贝构造函数的 参数只有一个且必须是类类型对象的引用 ,使用传值方式编

    2024年02月03日
    浏览(46)
  • [C++] 类与对象(中)类中六个默认成员函数(2)-- 运算符重载 -- 取地址及const取地址操作符重载

      本篇我们以日期类来展开讲。对于一个日期,我们如何去比大小呢?对年月日依次进行比较可以,但是可以直接比较吗? 我们可以看到,对于自定义类型的日期类直接去比较两个日期的大小是错误的,因此我们需要对运算符赋予特殊的功能,去实现可以对自定义类型的比较

    2024年02月13日
    浏览(52)
  • 【C++】运算符重载案例 - 字符串类 ⑤ ( 重载 大于 > 运算符 | 重载 小于 < 运算符 | 重载 右移 >> 运算符 - 使用全局函数重载 | 代码示例 )

    使用 成员函数 实现 等于判断 == 运算符重载 : 首先 , 写出函数名 , 函数名规则为 \\\" operate \\\" 后面跟上要重载的运算符 , 要对 String a , b 对象对比操作 , 使用 大于 运算符 , 使用时用法为 a b ; 函数名是 operate ; 然后 , 根据操作数 写出函数参数 , 参数一般都是 对象的引用 ; 要对

    2024年02月07日
    浏览(51)
  • C++——类和对象3|日期类型|Cout运算符重载|Cin运算符重载|const成员|

    目录 日期类型  Date.h  Date.cpp  Test.cpp  实现Cout运算符重载  实现Cin运算符重载  根据日期算星期  修改后完整代码   Date.h  Date.cpp  const成员  取地址及const取地址操作符重载 习题  计算日期到天数转换     一个类到底可以重载哪些运算符,要看哪些运算符对这个类型有

    2023年04月13日
    浏览(58)
  • C++ 面向对象(3)——重载运算符和重载函数

    C++ 允许在同一作用域中的某个 函数 和 运算符 指定多个定义,分别称为 函数重载 和 运算符重载 。 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。 当您调用一个 重载函数 或 重载运算符 时

    2024年02月10日
    浏览(56)
  • C++——类和对象之运算符重载

    本章思维导图: 注:本章思维导图对应的 xmind 文件和 .png 文件都已同步导入至”资源“ 我们都知道, 对于内置类型我们是可以直接用运算符直接对其进行操作的,但是对于自定义类型,这种做法是不被允许的 。 例如对于 Date 类: 因此, 为了解决自定义类型不能使用操作

    2024年02月05日
    浏览(49)
  • 十个 C++ 运算符重载示例,看完不懂打我...

    下面是一些 C++ 运算符重载示例,包括算术运算符、赋值运算符、逻辑运算符、成员运算符、关系运算符等等,这些都是使用频率较高的几个运算符重载案例。 ⭐️ 所有示例代码均存放于 GitHub: getiot/cpp-courses/operator_overloading 。 示例 1:一元运算符重载 一元运算符即只对一个

    2023年04月25日
    浏览(60)
  • 【C++初阶】五、类和对象(日期类的完善、流运算符重载函数、const成员、“&”取地址运算符重载)

    ========================================================================= 相关代码gitee自取 : C语言学习日记: 加油努力 (gitee.com)  ========================================================================= 接上期 : 【C++初阶】四、类和对象 (构造函数、析构函数、拷贝构造函数、赋值运算符重载函数)-CSD

    2024年02月05日
    浏览(49)
  • 【c++】类和对象(五)赋值运算符重载

    🔥个人主页 : Quitecoder 🔥 专栏 : c++笔记仓 朋友们大家好,本篇文章带大家认识赋值运算符重载,const成员,取地址及const取地址操作符重载等内容 运算符重载是一种编程语言特性,它允许开发者为已有的运算符提供自定义的实现。这意味着你可以改变某些运算符在你自定

    2024年04月10日
    浏览(45)
  • C++面向对象程序设计 - 运算符重载

            函数重载就是对一个已有的函数赋予新的含义,使之实现新的功能。因此一个函数名就可以用来代表不同功能的函数,也就是一名多用。运算符也可以重载,即运算符重载(operator overloading)。         运算符重载的方法是定义一个重载运算符的函数,在需要执行被

    2024年04月25日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包