目录
一、日期类
日期类主要用于深化对六大默认成员函数和运算符重载的理解
日期类需要实现方法有:
1.构造函数
2.拷贝构造函数
3.赋值运算符重载
4.==运算符重载
5.!=运算符重载
6.+运算符重载(主要是+天数)、+=运算符重载
7.-运算符重载(主要是-天数)、-=运算符重载
8.前置++运算符重载、后置++运算符重载
9.前置--运算符重载、后置--运算符重载
10.>运算符重载
11.<运算符重载
12.>= 、<=运算符重载
13.日期-日期 (返回天数)
14.析构函数
// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{
int arr[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 arr[month];
}
// 全缺省的构造函数
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::operator=(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
}
// 析构函数
Date::~Date()
{
_year = _month = _day = 0;
}
// 日期+=天数
Date& Date::operator+=(int day)
{
if (day < 0)
return *this -= day;
_day += day;
while (_day > GetMonthDay(_year, _month))
{
if (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
_month++;
}
if (_month > 12)
{
_year++;
_month = 1;
}
}
return *this;
}
// 日期+天数
Date Date::operator+(int day)
{
Date d(*this);
d._day += day;
while (d._day > GetMonthDay(d._year, d._month))
{
d._day -= GetMonthDay(d._year, d._month);
d._month++;
if (d._month > 12)
{
d._year++;
d._month = 1;
}
}
return d;
}
// 日期-天数
Date Date::operator-(int day)
{
Date d(*this);
d._day -= day;
while (d._day < 0 )
{
if (d._day < 0)
{
d._month--;
d._day += GetMonthDay(d._year, d._month);
}
if (d._month < 1)
{
d._year--;
d._month = 12;
}
}
return d;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
if (day < 0)
return *this += day;
_day -= day;
while (_day < 0)
{
if (_day < 0)
{
_month--;
_day += GetMonthDay(_year, _month);
}
if (_month < 1)
{
_year--;
_month = 12;
}
}
return *this;
}
// 前置++
Date& Date::operator++()
{
*this += 1;
return *this;
}
// 后置++
Date Date::operator++(int)
{
Date d(*this);
*this += 1;
return d;
}
//后置--
Date Date::operator--(int)
{
Date d(*this);
*this -= 1;
return d;
}
// 前置--
Date& Date::operator--()
{
*this -= 1;
return *this;
}
// >运算符重载
bool Date::operator>(const Date& d)
{
return (_year > d._year)
|| (_year==d._year&&_month > d._month)
|| (_year == d._year && _month == d._month && _day > d._day);
}
// ==运算符重载
bool Date::operator==(const Date& d)
{
return (_year == d._year) && (_month == d._month) && (_day == d._day);
}
// <运算符重载
bool Date::operator < (const Date& d)
{
return (_year < d._year)
|| (_year == d._year && _month < d._month)
|| (_year == d._year && _month == d._month && _day < d._day);
}
// >=运算符重载
bool Date::operator >= (const Date& d)
{
return !(Date::operator < (d));
}
// <=运算符重载
bool Date::operator <= (const Date& d)
{
return !(Date::operator > (d));
}
// !=运算符重载
bool Date::operator != (const Date& d)
{
return !(Date::operator == (d));
}
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
int flag = 1;
Date max = *this;
Date min = d;
int n = 0;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
while (max != min)
{
++min;
++n;
}
return n*flag;
}
void Date::Print()const
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
写完之后的体会:逻辑可能会有一些坑,要仔细想一想,保证完备性。否则会出各种各样的错误。最后一个计算日期之间相减的方法,我用了日期的前置++,调用了前置++的方法,前置++里面,又调用了+=的运算符重载,在+=这个方法里,我写了日期相加天数以后,超过本月天数和超过12个月的预防措施。因此不用担心日期相减和相加再出差错。最后一个日期相减的方法确实不容易想到,其他的都太繁琐了,这种方法比较简洁明了。
二、初始化列表
之前说了类里面有6个默认成员函数,其中构造函数和拷贝构造函数都可以在建立对象的时候就给对象赋值。虽然构造函数只能调用一次,但在这个函数里面,可以无数次给成员赋值。因此不叫初始化。
所谓初始化,是只能进行一次的。
虽然在构造函数里面也要进行赋值,但不管怎么样,类的成员都会走这个初始化列表,所以建议还是在初始化列表赋初始值。
class Date
{
public:
Date(int year, int month, int day)
:_year(year) //初始化年
,_month(month) //初始化月
,_day(day) //初始化天
{
}
private:
int _year =1900;
int _month = 1;
int _day = 1;
};
初始化列表的规则:
1.初始化列表的初始化顺序,是按照下面成员变量声明的顺序进行的,不是按照列表写在前后的顺序。
2.如果给了缺省值,又传了参数,那就用参数初始化,如果没给参数,那就用缺省值初始化。如果都没给,那就给随机值。
3.特别说明:const 修饰成员变量、引用的成员变量、自定义类型的成员(并且该类没有默认构造函数时)必须进行初始化。
int整型可以给自定义类型对象赋值,此时,int整型会通过拷贝构造给一个临时的对象,然后由这个临时对象给自定义类型对象赋值。如果加个explicit 关键词,就可以禁用构造函数的隐式转换。
三、static成员
static 修饰的成员变量叫静态成员变量,static修饰的成员函数,叫做静态成员函数。
1.static修饰的成员变量,不仅仅属于某一个对象,属于整个类,属于所有被类创建的对象。它可以通过类名访问,也可以通过某个对象访问。它的值会保存,随程序结束而销毁。
2.static修饰的成员变量,它不能在类中给缺省值。因为缺省值是给函数使用的,而且是this指针的函数。static属于类,它没有this指针。
3.static修饰的成员变量的定义,必须在类外。
4.静态成员也是类的成员,受public、private和protected访问限定符的影响。
static修饰的成员函数:
static修饰的成员函数,是专为static修饰的成员变量而生的,它只能访问static修饰的成员变量。不能访问非静态的成员变量。静态成员函数没有this指针。
class Date
{
public:
static int Getcount()//static修饰,返回int类型
{
return count;//获取静态成员变量的值
}
private:
static int count; //声明static成员变量
};
int Date::count = 0;//定义static成员变量
四、友元
前面介绍过友元。
在类中加上friend关键字,后面跟要声明的函数/类。就可以了。
这么写之后,该函数就是该类的朋友,函数可以使用类的成员(包括对象和函数),但是朋友是单向的,不是双向的。
一个函数可以是多个类的友元函数。
友元函数不能用const修饰。
友元类:
在Time类中,写了Date类的声明。Date类中没写Time类的友元声明。
则Time类的成员Date都可以访问,但Date类的成员,Time不能随意访问。
五、内部类
内部类是定义在类中的类。
内部类是外部类的友元。
内部类可以随意访问外部类的成员,但外部类不能随意访问内部类的成员。
sizeof(外部类)=外部类的大小,和内部类大小没有关系。
最后再强调一遍,类型是不会分配内存的。用类型实例化以后有了对象才会分配内存。