C++从零开始的打怪升级之路(day6)

发布时间:2024年01月11日

这是关于一个普通双非本科大一学生的C++的学习记录贴

在此前,我学了一点点C语言还有简单的数据结构,如果有小伙伴想和我一起学习的,可以私信我交流分享学习资料

那么开启正题

今天学习了const成员函数,把类的6个默认成员函数也收尾了,总结并实现了日期类

1.const成员函数

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

具体什么情况需要用到const指针呢,我们来观察下面的代码

class Date
{
public:
	Date(int year = 0, 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;
};

void Func(const Date& d) // 这里不用const修饰正常运行,用const编译器报错
{
	d.Print();
}

int main()
{
	Date d1(2024, 1, 10);
	Func(d1);

	return 0;
}

实际运用中,我们又经常会用到const来保护数据,难道我们不能用const了吗

答案肯定是否定的,我们首先要搞清楚,为什么上面的代码不能正常运行,在d调用Print函数的时候,涉及到传参,而d是一个被const修饰的对象,传参过去的Print的形参是this指针,虽然它没有改变对象的成员,但是它改变的权限,结合我们以前学的传参注意事项,我们不难发现,这里的传参是权限的放大,这是语法不支持的

void Print(const Date* this)
{
	cout << _year << "-" << _month << "-" << _day << endl;
}

但是this指针又是编译器默认写的,我们不能像上面这样写,这样会有"两个"this指针,而c++到底是怎样处理的呢,我们观察如下代码

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

C++在成员函数的括号后面加上const,表示这是一个const成员函数,this指针被const修饰,这样就很好的解决了我们的问题

因为非const可以调用const,而const不能调用非const,所以在我们编写成员函数的时候,就应该把能加上const的类尽量加上const来修饰

这里给读者留一些问题

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

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

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

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

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

class Date
{
public:
	Date* operator&()
	{
		return this;
	}

	const Date* operator&() const
	{
		return this;
	}

private:
	int _year;
	int _month;
	int _day;
};

这两个默认成员很简单,一般不需要我们来重载,使用编译器默认取地址重载即可,只有特殊情况才需要我们重载,比如想让别人获取到指定的内容(nullptr , 指定成员的地址)

3.日期类的实现

首先我们把要实现的函数和类的基本成员写在头文件中

class Date
{
public:
	//获取某月的天数
	int GetMonthDay(int year, int month)
	{
		static int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (month == 2 
			&& ((year % 400 == 0) || ((year % 4 == 0) && (year %100 != 0))))
			return 29;
		return days[month];
	}

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

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

	//赋值运算符重载
	Date& operator=(const Date& d);

	//逻辑运算符重载
	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);
	Date operator+(int day);
	Date operator-(int day);
	Date& operator++();//前置
	Date operator++(int);//后置
	Date& operator--();//前置
	Date operator--(int);//后置

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

	//析构函数
	~Date();

private:
	int _year;
	int _month;
	int _day;
};

首先实现我们最先学的函数

构造函数,拷贝构造函数,析构函数

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}

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

Date::~Date()
{
	_year = 0;
	_month = 1;
	_day = 1;
}

要注意的是,在类外定义成员函数要加上类名和访问限定符

再实现日期加减运算符重载

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)
{
	if (day < 0)
		return *this += -day;
	
	_day -= day;
	while (day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}

		_day += GetMonthDay(_year, _month);
	}

	return *this;
}

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

Date Date::operator-(int day)
{
	Date ret(*this);
	ret -= day;
	return ret;
}

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

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

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

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

上面代码用到了复用,它让我们减少了工作量,同时减小了维护所需的成本

再实现逻辑运算符重载

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 !(*this >= d);
}

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 _year == d._year && _month == d._month && _day == d._day;
}

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

再实现赋值运算符重载,为了实现连续赋值,我们函数的返回参数是调用这个函数的类

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

	return *this;
}

最后实现日期和日期之间的减法

因为进制很复杂,我们不能直接暴力相减,于是我们采用了逐值递增,判断相等,返回次数的方法,代码如下

int Date::operator-(const Date& d) const
{
	int count = 0;
	Date max = *this;
	Date min = d;
	if (d > *this)
	{
		max = d;
		min = *this;
	}

	while (max != min)
	{
		min++;
		count++;
	}

	return count;
}

总结::C++类和对象的基本特性已经基本熟悉了,六个默认成员函数也掌握了,接下来继续深入C++类和对象的学习

今天的博客就到这里了,后续内容明天分享,最近因为考试周原因不能更新太多内容,等考试周结束了再"快马加鞭"

新手第一次写博客,有不对的位置希望大佬们能够指出,也谢谢大家能看到这里,让我们一起学习进步吧!!!

文章来源:https://blog.csdn.net/2301_80764270/article/details/135513760
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。