隐式指针->this指针
什么叫隐式指针?
它其实就是在对象实例化以后,在传参的时候默认传过去的一个对象的地址
怎么理解这句话呢?
比如:我们的拷贝构造函数(不知到拷贝构造函数是干什么的可以往下看)
class Date
{
public:
// 构造函数
Date(int year = 1970, int month = 1, int day = 1)
:_year(year), _month(month), _day(day){}
// 这里就不做日期判断
// 拷贝构造函数
// 这里有隐含this指针
// 这里用const修饰是为了不希望在拷贝构造的时候修改我原有的值
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
// 析构函数
~Date();
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;
Date d1(d);
return 0;
}
上面的拷贝构造函数,当d1对象拷贝d对象时候,本应该传入两个参数,但只有一个,这里就有一个隐式的this指针 ,所以在拷贝函数里面也有两个形参
Date(const Date& d) -》 Date(Date *this, const Date& d)
Date d1(d); -》 Date d1(&d1, d);
理解这个再理解运算符重载就很简单了。
C++中默认六个成员函数
1. 构造函数
2. 拷贝构造函数
3. 析构函数
4. 赋值操作符重载
5. 取地址操作符重载
6. const修饰的取地址操作符重载
构造函数
构造函数分为有参和无参,是用来初始化类中的成员变量,所以在实例化一个对象时,就自动调用构造函数进行初始化。
构造函数的特征:
- 函数名与类名相同
- 无返回值
- 对象在实例化过程中自动调用
- 构造函数可以重载
- 如果没有构造函数,系统会自动添加一个无参数的构造函数
- 无参构造函数和全缺省的构造函数否认为是缺省构造函数,并且缺省的构造函数只能有一个。
拷贝构造函数
这是用来对需要创建同类对象时进行初始化用的。比如有个对象d1,我们需要有一个和d1一样参数的对象,这时我们就需要用拷贝构造函数。
特征:
- 拷贝构造可以说是构造函数的一个重载
- 拷贝构造时必须要用引用传参,如果用传值方式会发生无穷递归调用
- 如果为定义,系统会自动生成一个缺省的拷贝构造。
析构函数
析构函数是在对象生命周期结束时,系统会调用它来对对象进行一些清理工作
析构函数不能重载
析构函数无返回值
如果未定义,系统会自动生成缺省的析构函数
*运算符重载
运算符重载的特征:
poerator+合法运算符 构成运算符重载
注意:重载后不能改变运算符的优先级,结合性,操作数个数。
有五个运算符不能重载
.* / :: / sizeof / ?: / .
赋值运算符重载
这里要把赋值运算符重载和拷贝构造比较记忆
拷贝构造是创建对象时候,使用一个已有对象来为这个初始化
赋值运算的重载是对一个已经存在的对象进行拷贝赋值
到这里以日期类举例:
#include<iostream>
#include<windows.h>
#include<assert.h>
using namespace std;
class Date
{
public:
// 默认六大基本函数
// 构造函数>>你可以重载
// Date(); // 不能和全缺省的构造函数共存
Date(int, int, int);
bool IsLeapYear(int); // 判断是否是闰年
int GetMonthDay(int, int); // 得到该月的天数
// 拷贝构造函数
// 这里有隐含this指针
Date(const Date& d) // 这里用const修饰是为了不希望在拷贝构造的时候修改我原有的值
{
_year = d._year;
_month = d._month;
_day = d._day;
}
// 赋值操作符重载
// d1 = d2;函数栈帧结束,变量未释放&
// 不加Date&中的&,会多调用一次拷贝构造
Date& operator=(const Date& d) // 这个就相当于 Date& operator=(Date *this, const Date&d)
{
// 这里是如过要拷贝的对象是自己本身那么就不用拷贝直接返回
if (this == &d)
{
return *this;
}
// 这里有隐含的this指针
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
}
////////////////////////////
// 运算符重载
// 判断是否相等。
bool operator==(const Date& d)
{
if (_year == d._year && _month == d._month && _day == d._day)
{
return true;
}
return false;
}
bool operator!=(const Date& d)
{
if (!(*this == d))
{
return true;
}
return false;
}
bool operator>(const Date& d)
{
if (_year > d._year)
{
return true;
}
else if (_month > d._month)
{
return true;
}
else if (_day >d._day)
{
return true;
}
return false;
}
bool operator>=(const Date& d)
{
if (*this == d || *this > d)
{
return true;
}
return false;
}
bool operator<(const Date& d)
{
if (!(*this >= d))
{
return true;
}
return false;
}
bool operator<=(const Date& d)
{
if (*this < d || *this == d)
{
return true;
}
return false;
}
// 日期加上一个天数,d1 + 10;
// 不改变原来的d1,所以不能用引用
Date operator+(int day)
{
Date ret(*this);
if (day < 0)
{
ret -=(-day);
return ret;
}
ret._day += day;
while (GetMonthDay(ret._year, ret._month) < ret._day)
{
ret._day -= GetMonthDay(ret._year, ret._month);
if (ret._month == 12)
{
ret._month = 1;
++ret._year;
}
else
{
++ret._month;
}
}
return ret;
}
// 加等d1 = d1 + 10;
// 可以用引用,出了作用于变量还在
Date& operator+=(int day)
{
*this = *this + day;
return *this;
}
// 前置++和后置++
// 前置++
Date& operator++()
{
*this = *this + 1;
return *this;
}
// 后置++
Date operator++(int)// 用这样的方式来区分
{
Date ret(*this);
*this = *this + 1;
return ret;
}
// 日期减上天数
// 不能用引用
Date operator-(int day)
{
Date ret(*this);
if (day < 0)
{
ret += (-day);
return ret;
}
ret._day -= day;
while (ret._day <= 0)
{
if (ret._month == 1)
{
--ret._year;
ret._month = 12;
}
else
{
--ret._month;
}
// 因为前面已经相减为负数,所以要相加
ret._day += GetMonthDay(ret._year, ret._month);
}
return ret;
}
// 前置--和后置--
// 前置--
Date& operator--()
{
*this = *this - 1;
return *this;
}
// 后置--
Date operator--(int)
{
Date ret(*this);
*this = *this - 1;
return ret;
}
Date& operator-=(int day)
{
*this = *this - day;
return *this;
}
// 日期减去日期,求中间所差几天
int operator-(const Date& d)
{
int count = 0;
if (*this < d)
{
Date tmp(*this);
while (tmp != d)
{
++count;
++tmp;
}
}
else
{
Date tmp(d);
while (tmp != *this)
{
++count;
++tmp;
}
}
return count;
}
// 以上就是运算符重载
/////////////////////////////
void Print();
// 析构函数
~Date();
private:
int _year;
int _month;
int _day;
};
// 无参数构造函数 >> 并且你不能和全缺省构造参数一块出现
// Date::Date(){}
// 全缺省构造函数
Date::Date(int year = 1970, int month = 1, int day = 1) :_year(year), _month(month), _day(day)
{
if (!(year > 0 && month > 0 && month < 13 && day > 0 && day <= GetMonthDay(year, month)))
{
assert(false);
}
/*_year = year;
_month = month;
_day = day;*/
}
bool Date::IsLeapYear(int year)
{
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
{
return true;
}
return false;
}
int Date::GetMonthDay(int year, int month)
{
int days[13] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day = days[month];
if (day == 2 && IsLeapYear(year))
{
day = 29;
}
return day;
}
void Date::Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
// 你不能重载
Date::~Date(){}
int main()
{
Date d;
d.Print();
Date d1(2017, 2, 20);
d1.Print();
Date d2(2017, 2, 29);
d2.Print();
cout << d1.operator-(d2) << endl;
Date d3;
d3 = d2;
d3.operator+= (-100);
d3.Print();
system("pause");
return 0;
}
取地址操作符重载
这个重载和const修饰的取地址操作符重载相比前面四种默认函数,用的频率不是很高,一般系统生成的默认函数就够用了,但是这还是得了解。
就用日期类来说:Date *operator&(){} 这就是&重载。
const修饰的取地址操作符重载
先举例子
const Date *operator() const
如果了解const,就知道怎么用了,如果不了解,继续往下看。
最后两个默认成员函数后续继续更新