C++【类和对象】(取地址运算符重载与实现Date类)

敲代码的卓卓卓 2024-10-12 16:35:23 阅读 67

文章目录

取地址运算符重载const成员函数取地址运算符重载

Date类的实现Date.hDate.cpp1.检查日期合法性2. 构造函数/赋值运算符重载3.得到某月的天数4. Date类 +- 天数的操作4.1 日期 += 天数4.2 日期 + 天数4.3 日期 -= 天数4.4 日期 - 天数

5. Date的前后置++/--5.1 前置++5.2 后置++5.3 前置--5.4 后置--

6. Date类之间的比较6.1 < 操作符6.2 ==操作符6.3 <=操作符6.4 >操作符6.5 >=操作符6.6 !=操作符

7.日期-日期8. Date的流插入与流提取8.1流插入函数8.2 流提取函数

Test.cpp

结语

取地址运算符重载

const成员函数

将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后面。const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。const修饰Date类的Print成员函数,Print隐含的this指针由<code>Date* const this变成 const Date* const this

还是拿Date类举例,如果我用const 修饰的对象来调用Print会发生报错,原因是Print隐含的this指针是Date* const this,当我用const对象来调用Print会发生权限放大。

在这里插入图片描述

但是用const修饰成员函数,就可以解决问题,因为用const修饰后Print隐含的this指针由<code>Date* const this变成 const Date* const this,就不会出现权限放大。

#include<iostream>

using namespace std;

class Date

{ -- -->

public:

Date(int year = 1, int month = 1, int day = 1)

{

//cout << "这是构造函数" << endl;

_year = year;

_month = month;

_day = day;

}

//void Print(const Date* const this)

void Print() const

{

cout << _year << '/' << _month << '/' << _day << endl;

}

private:

int _year;

int _month;

int _day;

};

在这里插入图片描述

取地址运算符重载

取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载,⼀般这两个函数编译器自动生成的就可以够我们用了,不需要去显示实现。除非一些很特殊的场景,比如我们不想让别⼈取到当前类对象的地址,就可以自己实现⼀份,胡乱返回⼀个地址。

<code> Date* operator&()

{ -- -->

//return nullptr;(胡乱给的地址)

return this;

}

const Date* operator&() const

{

//return nullptr;(胡乱给的地址)

return this;

}

Date类的实现

我们在实现一个任务的时候,可以让声明与定义分离,这是一个好习惯。

Date.h

#pragma once

#include<iostream>

using namespace std;

class Date

{

public:

//1.检查日期的合法性

bool CheckDate();

//2.构造函数与赋值运算符重载

Date(int year = 1, int month = 1, int day = 1);

Date& operator=(const Date& d);

bool LeapYear(int year)

{

if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))

{

return true;

}

return false;

}

//3.得到某月天数

int GetMonthDay(int year, int month)

{

static int month_day[] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

if (month == 2 && LeapYear(year))

{

return month_day[month] + 1;

}

return month_day[month];

}

//4. Date类 +- 天数的操作

Date operator+(const int day);

Date& operator+=(const int day);

Date operator-(const int day);

Date& operator-=(const int day);

//5. Date的前后置++/--

Date& operator++();

Date operator++(int);

Date& operator--();

Date operator--(int);

//6. Date类之间的比较

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);

void Print();

//7. 日期-日期(算相差多少天)

int operator-(const Date& d);

//8. 日期的流插入与流提取

friend ostream& operator<<(ostream& out, Date& d);

friend istream& operator>>(istream& in, Date& d);

private:

int _year;

int _month;

int _day;

};

Date.cpp

实现前要包头文件

#include"Date.h"

1.检查日期合法性

//检擦日期合法性

bool Date:: CheckDate()

{

if (_month <= 0 || _month >= 13 ||

_day > GetMonthDay(_year, _month) || _day <= 0)

{

return false;

}

return true;

}

2. 构造函数/赋值运算符重载

构造函数

Date::Date(int year, int month, int day)

{

//cout << "这是构造函数" << endl;

_year = year;

_month = month;

_day = day;

while (!CheckDate())

{

cout << "非法日期" << endl;

cout << *this;

cout << "请重新输入日期" << endl;

cin >> *this;

}

}

其实我们是不需要写拷贝构造和赋值运算符重载,因为Date类内部的成员对象并没有指向资源。

但是我们写赋值运算符重载是为了实现连续赋值。

Date& Date::operator=(const Date&d)

{

//如果不是自己给自己赋值

if (this != &d)

{

_year = d._year;

_month = d._month;

_day = d._day;

}

//d1 = d2 应该返回前者(因为前者是被改变的) 所以要返回*this

return *this;

}

3.得到某月的天数

因为GetMonthDay这个函数会被频繁大量的调用,所以我们放在类里面定义(类里面的函数默认inline展开)

//判断闰年(其实这个函数没必要写,但我为了美观就写了该函数)

bool LeapYear(int year)

{

if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))

{

return true;

}

return false;

}

//得到某月的天数

int GetMonthDay(int year, int month)

{

//将month_day静态化,这样就不用反复的创建数组

static int month_day[] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

if (month == 2 && LeapYear(year))

{

return month_day[month] + 1;

}

return month_day[month];

}

4. Date类 ± 天数的操作

加减的是天数

4.1 日期 += 天数

加等使用的是进位思想,当这个月满了,向下个月借天数(同时月份也会+1)当月份大于12时,就将年份+1,同时月份到一月,直到日期为合法。

Date& Date::operator+=(const int day)

{

if (day < 0)

{

return *this -= (-day);

}

_day += day;

while (_day > GetMonthDay(_year,_month))

{

int tmp = GetMonthDay(_year, _month);

_day -= tmp;

++_month;

if (_month > 12)

{

_month = 1;

++_year;

}

}

return *this;

}

4.2 日期 + 天数

这里我们可以直接复用 日期+=天数 !

Date Date::operator+(const int day)

{

Date tmp(*this);

tmp += day;

return tmp;

}

4.3 日期 -= 天数

-=与+=的实现十分类似,只不过-=使用的是退位的思想,向前一个月借天数(月份-1),当月份小于1,年份-1,月份到12月,直到日期合法

Date& Date:: operator-=(const int day)

{

if (day < 0)

{

return *this += (-day);

}

_day -= day;

while (_day <= 0)

{

--_month;

if (_month == 0)

{

_month = 12;

--_year;

}

int tmp = GetMonthDay(_year, _month);

_day += tmp;

}

4.4 日期 - 天数

和+一样,复用-=

Date Date::operator-(const int day)

{

Date tmp = *this;

tmp -= day;

return tmp;

}

5. Date的前后置++/–

前置不需要加入int形参,后置需要加入int形参。

5.1 前置++

复用+=

Date& Date::operator++()

{

*this += 1;

return *this;

}

5.2 后置++

在参数位置上加一个int形参

Date Date::operator++(int)

{

Date tmp = *this;

*this += 1;

return tmp;

}

5.3 前置–

Date& Date::operator--()

{

*this -= 1;

return *this;

}

5.4 后置–

Date Date::operator--(int)

{

Date tmp = *this;

*this -= 1;

return tmp;

}

6. Date类之间的比较

完成 < + == 或者 > + ==其他的比较就可以复用了。

本文实现的是 < + ==

6.1 < 操作符

bool Date:: operator<(const Date& d)

{

if (_year > d._year)

{

return false;

}

else if (_year == d._year)

{

if (_month >= d._month)

{

return false;

}

else if (_month == d._month)

{

if (_day >= d._day)

{

return false;

}

}

}

return true;

}

6.2 ==操作符

bool Date::operator==(const Date& d)

{

return _year == d._year &&

_month == d._month &&

_day == d._day;

}

6.3 <=操作符

bool Date::operator<=(const Date& d)

{

return (*this < d) || (*this == d);

}

6.4 >操作符

bool Date::operator>(const Date& d)

{

return !(*this <= d);

}

6.5 >=操作符

bool Date::operator>=(const Date& d)

{

return !(*this < d);

}

6.6 !=操作符

bool Date::operator!=(const Date& d)

{

return !(*this == d);

}

7.日期-日期

我们使用最简单的思路,取到区分较大和较小的日期,让较小的日期+1加到与较大的日期相等,同时记加了多少次,就得到了日期之间的天数。(cup的运行速度超级快,每秒上亿次,所以这点运算量对于cup来说轻轻松松)

//Date-Date

int Date::operator-(const Date& d)

{

int n = 0;

int flag = 1;

//假设法

Date min = *this;

Date max = d;

if (min > max)

{

min = d;

max = *this;

flag = -1;

}

//计算天数

while (min != max)

{

++min;

++n;

}

return n * flag;

}

8. Date的流插入与流提取

8.1流插入函数

ostream& operator<<(ostream& out, Date& d)

{

cout << d._year << '/' << d._month << '/' << d._day << endl;

return out;

}

注意,这里流插入和流提取都是全局函数,而非类的成员函数,其实我们在类里面也可以实现,但是会很怪。

由于成员函数的第一个参数默认是this,但运算符重载的规定是,当两个变量使用重载的运算符,会将左边的变量视为第一个参数,右边的变量视为第二个参数;这样的话,我们就不能写成cout << Date类实例化的对象,而是要写成Date类实例化的对象 << coutcin同理。

但是这样并不符合我们的习惯,所以我们设置成了全局函数,但是全局函数又有一个问题,就是Date类内部的成员变量是私有的,外部不能访问。

对此我们有以下几个方法:

将成员变量公有化(最最最不推荐的方法)用get函数来得到成员变量使用友元函数放到类的内部(因参数问题不考虑)

这里我们使用的是友元函数(后面会详细讲解)。

8.2 流提取函数

istream& operator>>(istream& in, Date& d)

{

cin >> d._year >> d._month >> d._day;

while (!d.CheckDate())

{

cout << "非法日期" << endl;

cout << d;

cout << "请重新输入日期" << endl;

cin >> d;

}

return in;

}

Test.cpp

#include"Date.h"

void Test1()

{

Date d1;

Date d2(2026, 2, 28);

//Date d3(2029, 9, 33);

Date d3(2029, 9, 30);

d1.Print();

d2.Print();

d3.Print();

d3 = d2 = d1;

d1.Print();

d2.Print();

d3.Print();

}

void Test2()

{

Date d1(2026, 2, 28);

d1 += 10000;

d1.Print();

d1 -= 10000;

d1.Print();

Date d2 = d1 + 10000;

d2.Print();

Date d3 = d1 - 10000;

d3.Print();

}

void Test3()

{

Date d1(2026, 2, 28);

Date d2 = ++d1;

d2.Print();

Date d3 = d1++;

d3.Print();

Date d4 = --d1;

d4.Print();

Date d5 = d1--;

d5.Print();

}

void Test4()

{

Date d1(2024, 9, 28);

Date d2(2026, 2, 28);

cout << (d1 == d2) << endl;

cout << (d1 != d2) << endl;

cout << (d1 < d2) << endl;

cout << (d1 <= d2) << endl;

cout << (d1 > d2) << endl;

cout << (d1 >= d2) << endl;

}

void Test5()

{

Date d1(2024, 9, 28);

Date d2(2026, 2, 28);

cout << d1 - d2 << endl;

}

void Test6()

{

Date d1;

cin >> d1;

cout << d1;

}

int main()

{

//Test1();

//Test2();

//Test3();

//Test4();

//Test5();

Test6();

return 0;

}

结语

这次的分享就到这里结束了~

最后感谢您能阅读完此片文章~

如果您认为这篇文章对你有帮助的话,可以用你们的手点一个免费的赞并收藏起来哟~

如果有任何建议或纠正欢迎在评论区留言~

也可以前往我的主页看更多好文哦(点击此处跳转到主页)。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。