日期Date代码:
.h:
#pragma once
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1);
void print();
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& in, Date& d);
int Get_Month_day(int year, int month)
{
static 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[year];
}
Date(const Date& d);
Date& 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);
bool operator!=(const Date& d);
int operator-(const Date& d);
Date& operator+=(int x);
Date operator+(int x);
Date& operator-=(int x);
Date operator-(int x);
Date& operator++();
Date operator++(int);
~Date();
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d);
istream& operator>>(istream& in, Date& d);
.cpp:
#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"
Date::Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
Date::~Date()
{
_year = -1;
_month = -1;
_day = -1;
}
void Date::print()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
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;
}
bool Date::operator>(const Date& d)
{
if (_year > d._year)
{
return true;
}
else if (_year == d._year)
{
if (_month > d._month)
{
return true;
}
else if (_month == d._month)
{
if (_day > d._day)
{
return true;
}
}
}
return false;
}
bool Date::operator==(const Date& d)
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
bool Date::operator<(const Date& d)
{
return !((*this > d) || (*this == d));
}
bool Date::operator>=(const Date& d)
{
return (*this > d) || (*this == d);
}
bool Date::operator<=(const Date& d)
{
return (*this < d) || (*this == d);
}
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
int Date::operator-(const Date& d)
{
Date tem(d);
int count = 0;
while (tem != *this)
{
tem++;
++count;
}
return count;
}
Date& Date::operator+=(int x)
{
_day += x;
while (_day > Get_Month_day(_year, _month))
{
_day -= Get_Month_day(_year, _month);
_month++;
if (_month == 13)
{
_month = 1;
_year++;
}
}
return *this;
}
Date Date::operator+(int x)
{
Date tem(*this);
tem += x;
return tem;
}
Date& Date::operator-=(int x)
{
_day -= x;
while (_day < 0)
{
_month--;
if (_month == 0)
{
_month = 12;
_year--;
}
_day += Get_Month_day(_year, _month);
}
return *this;
}
Date Date::operator-(int x)
{
Date tem(*this);
tem -= x;
return tem;
}
Date& Date::operator++()
{
++_day;
if (_day > Get_Month_day(_year, _month))
{
_day -= Get_Month_day(_year, _month);
++_month;
if (_month == 13)
{
_month = 1;
_year++;
}
}
return *this;
}
Date Date::operator++(int)
{
Date tem(*this);
++(*this);
return tem;
}
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << "日";
return out;
}
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
基本知识点:
1.访问限定符有三个:
public(公有)
private(私有)
protected(保护)
2.面向对象的是三个特性:封装,集成,多态
3.空类的大小是1,但他不存储有效数据,仅仅是用来表示变量被定义出来
4.关于this指针:
在d1调用Init函数的时候,编译器就自动给你将当前对象即d1的地址传过去
Init函数也会自动用this指针作为第一个参数来接收
注:你不能在形参那里显式写this指针,但是你可以在函数里边用
六个默认成员函数:
5.类中会自动生成六个默认成员函数(我们写了,编译器就不会默认生成了):
构造和析构
拷贝和赋值
取地址和他的重载(这两个用的很少)
构造函数:
构造函数特征:
(1).函数名与类名相同
(2).无返回值类型
(3).在对象实例化时编译器会自动调用对应的构造函数
(4).构造函数可以重载
注:编译器自动生成的默认构造函数特点:
默认对自定义类型(类那些)调用该类型变量的无参构造
对内置类型(int那些)没有规定要不要处理
注意套娃
析构函数:
析构函数特征:
(1).析构函数名是类名前加上~
(2).无参数无返回值类型
(3).一类只能有一个析构函数,即:不能重载
(4).在对象生命周期结束时,编译器会自动调用该析构函数完成对资源的清理和释放工作
注:变量的析构顺序按照构造的相反顺序进行析构,即:
构造顺序:ABCD 则析构顺序:DCBA,但是要注意全局变量和static修饰的变量要在程序结束后才进行析构,二者的析构顺序也符合 变量的析构顺序按照构造的相反顺序进行析构 即先析构局部变量,再析构全局变量和static修饰的变量
注:编译器自动生成的默认析构函数特点:
对自定义类型调用它对应的析构函数
对内置类型没有规定要不要进行处理
构造函数和析构函数的一些小小区别:
构造函数不能显式调用,但是析构函数可以
6.无参数的构造和全缺省构造以及编译器自动生成的构造都被称为默认构造
无参构造即不用传参就能完成的构造
拷贝构造:
7.拷贝构造函数是构造函数的一种重载形式
注:拷贝构造函数的参数只有一个且必须是类类型的引用
8.编译器默认生成的拷贝构造只是浅拷贝,对自定义类型来说没什么问题,但是对于自定义类型来说就会有问题。例:
类里边定义了一个数组,然后用d1拷贝构造造出了d2,那么d2里边的数组空间就是d1里边的数组空间,如此一来,在析构的时候就会对该数组的空间进行两次的free造成程序崩溃
且编译器自动生成的拷贝构造会对内置类型进行浅拷贝,对自定义类型调用它的拷贝构造
注:自己写了默认构造,不影响编译器自己生成拷贝构造
赋值拷贝:
1.赋值操作符的返回值是左操作数
2.参数类型是const Date&,引用可以提高效率,const可以避免右操作数被修改
返回值类型:Date& ,返回的是*this
要检测是否自己给自己赋值
3.编译器自动生成的复制拷贝对内置类型进行浅拷贝,对自定义类型调用它的赋值拷贝
4.赋值拷贝不是构造函数
赋值拷贝与拷贝构造的区别:
赋值拷贝是将一个对象赋值给另一个已经创建好了的对象
但是拷贝构造是讲一个对象拷贝给另一个将要创建的对象
运算符重载:
1.重载运算符必须至少有一个类类型参数
2. 5个不能重载的运算符:.* ? : . sizeof ::
3.运算符重载是具有特殊函数名的函数(有返回值和参数列表)
传值返回和引用返回的区别:
传值返回会生成临时对象,所以就会有一次拷贝构造和析构,
临时对象再拷贝构造给接收返回值的变量,那么又会有一次的拷贝构造和析构
这里总共就会有两次的拷贝构造和析构
引用返回可以减少那个对临时对象的拷贝构造和析构,因此总共就只有一次的拷贝构造和析构
这样看来,引用返回的效率就比传值返回的效率更高。
但是:用引用返回是有风险的:用了引用返回,编译器生成的临时对象就是返回值的别名,然而在函数结束的时候该函数栈帧就已经被释放了,所以此时的临时对象里边存放的就是经过了析构函数的调用后的返回值,因此这里边存放的就可能不是原来返回值的数据,就可能出现运行错误。
因此:对于函数结束后该返回值还不会销毁的才能够用引用返回。
一些其他知识点:
1.当类的成员函数的this指针指向的内容不能修改时:
要在函数的定义和声明末尾那里同时加上 const
2.前提:A是一个类的类型,它的构造函数参数只有this指针和int x
则A a1 = 3;也可以完成构造,但它发生了隐式类型转换,即:
先用3来构造一个临时变量,再用临时变量去构造a1
3.用static修饰成员变量,则该成员变量属于整个类,且其存放在静态区,不能给缺省值
且初始化必须在全局那里初始化
用static修饰成员函数,那么该成员函数没有this指针,只能访问静态成员