类和对象(中)+日期类的实现
文章目录
一、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.思考
- const对象可以调用非const成员函数吗?
不可以,因为const修饰的对象为只读类型,若调用非const非成员函数,属于权限放大行为
,只读权限变成既可以读又可以可写。
- 非const对象可以调用const成员函数吗?
可以,因为非const对象权限拥有可读、可写权限,调用const成员函数属于权限缩小
问题,权限变为只读。
- const成员函数内可以调用其它的非const成员函数吗?
不可以,因为const修饰的成员函数为只读类型,若调用非const非成员函数,属于权限放大行为
,只读权限变成既可以只读又可以可写。
- 非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;
}