this指针
可以看到d1,d2都调用了print函数,可是为什么他们在相同的函数找到自己的值呢,这就是隐藏的this指针发挥了作用
那么this指针存在哪里的呢?
因为this指针是形参,所以一般情况下是栈
构造函数
c语言有时候会忘记写初始化函数,所以为了方便,就有了构造函数
构造函数特征:1.函数名和类名相同 2.没有返回值 3.对象实例化时自动调用 4.可以重载
如果类中没有显示定义构造函数,编译器会自动生成一个无参的默认构造函数,一旦用户显示定义,编译器将不再生成
c++里面把函数分成两类:内置类型,自定义类型
内置类型:如int,char,指针等 自定义类型:自己定义的类型,如class,struct等
任何一个类的默认构造函数就是不用参数就可以调用的函数,有三个:全缺省,无参,编译器默认生成的
我们不写编译器默认生成构造函数,构造函数对于内置类型不做处理,对于自定义类型会去调用它的默认构造函数(不用参数就可以调用的),如果没有默认构造函数就会报错
析构函数
对象在销毁时会自动调用析构函数,完成一些资源清理工作
析构函数特征:1.在类名面前加~ 2.无返回值 3.一个类只有一个析构函数。如果未显示定义,系统会自动生成默认的析构函数 4.对象生命周期结束时,c++编译系统自动调用析构函数
析构函数先存入的后释放
如果我们不写默认生成的析构函数和构造函数类似
对于内置类型不处理·对于自定义类型会去调用它的析构函数
拷贝构造
特征:1.拷贝构造是构造函数的一个重载形式
2.拷贝构造的参数只有一个且必须使用引用传参,使用传值传参会引发无穷递归调用(调用拷贝构造需要先传参,传值传参又是一次拷贝构造)
3.若未显示定义,系统默认生成拷贝构造
默认拷贝构造对于1,内置类型:会完成按字节序的拷贝构造(浅拷贝) 2,自定义类型:会调用它的拷贝构造
总结:拷贝构造我们不写,生成的默认拷贝构造函数对于内置类型和自定义类型都会进行拷贝处理,但是处理细节是不一样的
运算符重载
语法:返回值类型 operator 操作符(参数列表)
例如比较大小d1>d2就可以调用运算符函数,那是因为编译器可以将d1>d2转换成operator>(d1,d2)
这样就可以看出运算符重载的作用就是增强代码的可读性
(:: sizeof ?: . .*)五个运算符不能进行重载
赋值运算符重载
编译器默认生成赋值重载,跟拷贝构造做的事情完全类似
一个已经存在的对象初始化一个马上创建实例化的对象是拷贝构造
两个已经存在的对象之间是赋值重载
if中this是指针,&d是取地址而不是引用。比较的是地址
日期类的实现
头文件
#pragma once
#include<iostream>
using namespace std;
class Date
{
public:
Date(int _year = 0, int _month = 1, int _day = 1);
void print();
int getmonthday(int year, int month);
bool operator>(const Date& x)const;
bool operator==(const Date& x)const;
bool operator>=(const Date& x)const;
bool operator<=(const Date& x)const;
bool operator<(const Date& x)const;
bool operator!=(const Date& x)const;
Date operator=(const Date& x);
Date operator++();
Date operator++(int);
Date& operator+=(int day);
Date& operator-=(int day);
Date operator+(int day);
Date operator-(int day);
int operator-(const Date& x)const;
void printweekday()const;
private:
int _year;
int _month;
int _day;
};
构造函数,打印函数和这个月天数的获取
Date::Date(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
if (!(_year > 0 && (_month > 0 && _month < 13) && (_day > 0 && _day <= getmonthday(_year,_month))))
{
cout<<"数据有误"<<endl;
}
}
void Date::print()
{
cout<<_year<<" "<<_month<<" "<<_day<<endl;
}
int Date::getmonthday(int _year, int _month)
{
int montharray[] = {0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int _day = montharray[_month];
if (_month == 2 && (_year % 100 != 0 && _year % 4 == 0) || (_year % 400 == 0))
{
_day += 1;
}
return _day;
}
前置++和后置++
Date Date::operator++()
{
*this += 1;
return *this;
}
Date Date::operator++(int)
{
Date tmp(*this);
*this+= 1;
return tmp;
}
c++为了辨别前置++和后置++在参数里面加入了int来进行区分,加了int参数的就是后置++
前置++是直接返回++之后的值,后置++是返回原来的值,下一次进行++
所以后置++要将值进行拷贝构造入tmp,然后自己++,返回tmp这样下次就是++之后的值了
判断日期大小的重载
bool Date::operator>(const Date& x)const
{
if (this->_year > x._year)
{
return true;
}
if (_year == x._year && _month > x._month)
{
return true;
}
if (_year == x._year && _month == x._month && _day > x._day)
{
return true;
}
else
{
return false;
}
}
bool Date::operator==(const Date& x)const
{
return _year == x._year &&
_month == x._month &&
_day == x._day;
}
bool Date::operator>=(const Date& x)const
{
return (*this > x)||(*this == x);
}
bool Date::operator<=(const Date& x)const
{
return !(*this>x);
}
bool Date::operator<(const Date& x)const
{
return !(*this>=x);
}
bool Date::operator!=(const Date& x)const
{
return !(*this == x);
}
将>和==写出来,其他的进行复用即可
日期减天数和加天数
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -day;
}
_day -= day;
while(_day <=0)
{
_day += getmonthday(_year, _month);
_month--;
if (_month == 0)
{
--_year;
_month = 12;
}
}
return *this;
}
Date Date::operator-(int day)
{
Date tmp(*this);
tmp -= day;
return tmp;
}
一个日期减去天数得到的是日期,所以返回值是Date,因为返回的日期不会进行销毁,所以返回值带引用,这样可以减少拷贝,总体思路是不管怎么样先将天数减掉,如果减的天数太大,那么调整月进而调整年。如果减的是负数就是相当与加正数,将+=进行复用。减等自身会变但是减自身不会变,所以写完减等就可以进行复用。
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)
{
_month = 1;
_year += 1;
}
}
return *this;
//*this没有被施放使用引用返回减少拷贝
}
Date Date::operator+(int day)
{
//+不能改变本身
Date tmp(*this);
tmp += day;
return tmp;
}
加和减是一样的思路,同时如果加的是负数就是去减负数,将-=进行复用
两个日期间隔多少天
int Date::operator-(const Date& x)const
{Date max = *this;
Date min = x;
int flag = 1;
if (*this<x)
{
min = *this;
max = x;
flag = -1;
}
int count = 0;
while (max!=min)
{
++min;
++count;
}
return count*flag;
}
总体思路是让小的那个自己一直加直到找到大的那个
关键问题是不知道哪个是大是小,所以我们假设,如果假设错误再进行反转
查看日期是星期几
void Date::printweekday() const
{
const char* arr[] = { "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天" };
//Date start(1900, 1, 1);
//int count = *this - start;
int count = *this - Date(1900, 1, 1);
cout << arr[count % 7] << endl;
}
这里*this-start可以进行匿名函数处理成*this-Date(1900,1,1)
流插入和流提取重载
ostream& operator<<(ostream& _cout)
{
_cout << _year << "-" << _month << "-" << _day << endl;
return _cout;
}
我们在重载流插入运算符时发现上面那种方法不行,为什么呢?
我们看到在类里面this指针是指向d1的,所以第一种方法写反了,因该是d1<<cout,但是这样写就会看到与平常流插入的顺序是相反的,所以我们写流插入运算符重载时尽量不要在类里面写,但是到外面写,就访问不到类里面的成员变量了这样就有了友元函数
friend ostream& operator<<(ostream& _cout, const Date& d);
friend istream& operator>>(istream& _cin, Date& d);
在函数前面加friend就可以代表友元函数,这样就可以访问到类里面的对象了