类和对象(中)+日期类的实现

类和对象(中)+日期类的实现

一、const成员函数

1.概念

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

2.基本使用

基本的修饰方法如下,在函数的括号后加const即可

void Print()const
{
	cout<<_year<<"/"<<_month<<"/"<<_day<<endl;
}

实际修饰的是该函数隐含的this指针。

this指针本身是Date*const类型的,修饰后变为const Date* const类型。

在这里插入图片描述

3.权限问题

我们之前学过const,const修饰的变量,只可读不可改。

那成员函数中为什么要用const修饰呢?

我们用一个简单的例子来说明:

class Date {
public:
    Date(int year = 2022, int month = 10, int day = 10)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print()const
    {
        cout << _year << "/" << _month << "/" << _day << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};

此时我们调用Print函数时还可以正常使用。

int main()
{
    Date d1;
    d1.Print();
    return 0;
}

但是使用一个只可读的d2,此时就无法使用Print函数了。

int main()
{
	const Date d2;
    d2.Print();
    return 0;
}

原因是:

Print的形参是Date const*指针。

  • d1调用Print,传入的是Date*指针
  • d2调用Print,传入的是const Date*指针

在这里插入图片描述

而给Print加了const

在这里插入图片描述

如果我们在函数后面加了const,就可以避免此种权限放大问题。这样不管是d1还是d2中对Print()函数的调用,就都可以正常打印了。

4.思考
  1. const对象可以调用非const成员函数吗?

不可以,因为const修饰的对象为只读类型,若调用非const非成员函数,属于权限放大行为,只读权限变成既可以读又可以可写。

  1. 非const对象可以调用const成员函数吗?

可以,因为非const对象权限拥有可读、可写权限,调用const成员函数属于权限缩小问题,权限变为只读。

  1. const成员函数内可以调用其它的非const成员函数吗?

不可以,因为const修饰的成员函数为只读类型,若调用非const非成员函数,属于权限放大行为,只读权限变成既可以只读又可以可写。

  1. 非const成员函数内可以调用其它的const成员函数吗?

可以,因为非const成员函数权限拥有可读、可写权限,调用const成员函数属于权限缩小问题,权限变为只读。


还是那句话,权限只可以缩小,不能够放大。也就是我本身只能是可读的(const),不能传过去编程可读可写的了(非const)。

我们可以合理的判断出:只要是需要修改类中成员变量的函数,就不需要在()后面加const修饰。

如果一个函数中不需要修改成员变量,就可以加const进行修饰。

注意:如果你用了声明和定义分离的写法,那么声明和定义的函数都需要加上const修饰

二、取地址重载及const取地址重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

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

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

三、小结

  • 构造函数

    初始化,内置类型需要手动实现。

  • 析构函数

    清理资源,和我们数据结构写过的Destroy很像,申请过空间就必须手动实现。

  • 拷贝构造函数

例如:

Date d1;//构造
Date d2(d1);//拷贝构造
Date d3 = d1;拷贝构造
  • 赋值构造函数
Date d1;//构造
Date d2;//构造
d2 = d1;//赋值构造

拷贝构造和赋值构造不同之处在于:

  • 拷贝构造创建一个对象同时拿同类对象进行初始化的拷贝。
  • 赋值构造是两个同类对象已经存在,只是将一个对象复制拷贝给另一个对象。

四、日期类实现

Date.h
#include <iostream>
using namespace std;
class Date
{
public:
	// 获取某年某月的天数
	int GetMonthDay(int year, int month)
	{
		static int MonthOfDay[13] = { 0,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 29;
		}
		return MonthOfDay[month];
	}

	// 全缺省的构造函数
	Date(int year = 1900, 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 Print()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}

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

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

	// 析构函数
	/*~Date()
	{

	}*/

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

	// >运算符重载
	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;

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

private:
	int _year;
	int _month;
	int _day;
};
Date.cpp
#include "Date.h"

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)const
{
	Date ret(*this);
	ret += day;
	return ret;
}

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-(int day)const
{
	Date ret(*this);
	ret -= day;
	return ret;
}


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

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--()
{
	return *this -= 1;
}

bool Date::operator>(const Date& d)const
{
	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;
	return false;
}

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

bool Date::operator >= (const Date& d)const
{
	return *this > d || *this == d;
}

bool Date::operator < (const Date& d)const
{
	return !(*this >= d);
}

bool Date::operator <= (const Date& d)const
{
	return !(*this > d);
}

int Date::operator-(const Date& d)const
{
	Date max = *this;
	Date min = d;
	int flag = 1;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	int n = 0;
	while (max != min)
	{
		++n;
		++min;
	}
	return n * flag;
}

bool Date::operator != (const Date& d)const
{
	return !(*this == d);
}
test.cpp
#include "Date.h"
void test1()
{
	Date d1(2022, 10, 10);
	Date d2 = d1;
	d2.Print();
}

void test2()
{
	Date d1(2022, 10, 10);
	Date d2(2022, 11, 10);
	cout << (d1 - d2) << endl;
}

void test3()
{
	Date d1(2022, 10, 10);
	(d1++).Print();
	d1.Print();
	d1 += 500;
	d1.Print();
	d1 -= 500;
	d1.Print();
	Date d3(2022, 10, 10);
	Date d4(2022, 11, 10);
	cout << (d3 - d4) << endl;
	Date d5(2022, 10, 10);
	Date d6 = d5;
	d6.Print();
}

int main()
{
	test3();

	return 0;
}

1()
{
Date d1(2022, 10, 10);
Date d2 = d1;
d2.Print();
}

void test2()
{
Date d1(2022, 10, 10);
Date d2(2022, 11, 10);
cout << (d1 - d2) << endl;
}

void test3()
{
Date d1(2022, 10, 10);
(d1++).Print();
d1.Print();
d1 += 500;
d1.Print();
d1 -= 500;
d1.Print();
Date d3(2022, 10, 10);
Date d4(2022, 11, 10);
cout << (d3 - d4) << endl;
Date d5(2022, 10, 10);
Date d6 = d5;
d6.Print();
}

int main()
{
test3();

return 0;

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值