拷贝构造
构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
特征
拷贝构造函数也是特殊的成员函数,其特征如下:
- 拷贝构造函数是构造函数的一个重载形式。
- 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
具体实现
class Date
{
public:
Date(int year = 2020, int month = 4, int day = 15)
{
_year = year;
_month = month;
_day = day;
}
//Date b = a; 相当于 Date& d = a; 此时d 就是 a 的别名,this指针指向b, 把d的值给b就是把a的值给b
Date(Date& d) //const可以加可以不加
{
_year = d._year; //相当于 this->_year = a._year;
_month = d._month; //this->_month = a._month;
_day = d._day; //this->_dat = a._day;
}
//const可以加可以不加
Date(Date d)//如果不加&, 就会变成 Date d = a,再递归 Date d = a,-------无限的递归下去,直到栈溢出,所以C++不允许这种无限递归拷贝构建存在
{
_year = d._year;
_month = d._month;
_day = d._day;
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
//void func(Date& d1) Date& d1 = a; 此时d1 就是 a 的别名,不用再向下面一样去再次递归调用了
void func(Date d1)// Date d1 = a; Date& d = a; d就是a的别名,然后再返回去得到 func(d) 此时d是a的别名,相当于func(a)
{} //这两中方式都不会造成无限的递归拷贝构造
int main()
{
Date a;
Date b = a;
//Date b(a);
//这两种方式都是拷贝构造
func(a);
b.print();
}
无限递归拷贝构建的流程图
再借用《剑指offer》中的一道例题来解释
以下
class A {
private:
int value;
public:
A(int n)
{
value = n;
}
A(A other)
{
value = other.value;
}
void Print()
{
cout << value << endl;
}
};
int main(void)
{
A a = 10;
A b = a;
b.Print();
return 0;
}
对上面这段代码进行分析编译运行的结果是:
A、编译错误 B、编译成功,运行时程序崩溃 C、编译运行正常,输出10
正确答案是 A
A a = 10; //这是实例化一个对象a并且让a.value = 10
A b = a; //这里就出问题了,传参后是A other = a,然后再递归传参 A other = a,然后递归传参,这杨就会构成无限递归拷贝构建,所以会导致编译出错
A(A& other) //改成这样就能成功运行了
{
value = other.value;
}
赋值运算符重载
描述
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:
- 不能通过连接其他符号来创建新的操作符:比如operator@
- 重载操作符必须有一个类类型或者枚举类型的操作数
- 用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义
- 作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的操作符有一个默认的形参this,限定为第一个形参
- "."(成员访问运算符) 、 " sizeof "(长度运算符)、 " :: "(域运算符)、
" . * " (成员指针访问运算符) 、" ?: "(条件运算符)
注意以上5个运算符不能重载。
运算符重载具体实现(内含const修饰 this 指针)
class Date
{
private:
int _year;
int _month;
int _day;
public:
int GetMonthDay(int year, int month)
{
static int monthDays[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// 是2月且是闰年返回29
if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
{
return 29;
}
return monthDays[month];
}
Date (int year = 1, int month = 1, int day = 1)
{
if (year > 0 && (month > 0 && month < 13) && (day > 0 && day <= GetMonthDay(year, month)))
{
_year = year;
_month = month;
_day = day;
}
else
cout << "非法日期" << endl;
}
// < == > <= >= !=
inline bool operator<(const Date& d) const //const 是给 this 指针加的,这样即使你创建一个const类型的对象也能保证能够传值,因为this指针不可见,所以用后置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;
}
inline bool operator==(const Date& d) const
{
return _year == d._year && _month == d._month && _day == d._day;
}
inline bool operator>(const Date& d) const
{
return !(*this < d || *this == d);
}
bool operator<=(const Date& d) const
{
return !(*this > d);
}
bool operator>=(const Date& d) const
{
return !(*this < d);
}
bool operator!=(const Date& d) const
{
return !(*this == d);
}
//-= += + - 前置-- 后置-- 前置++ 后置++
//d1 += 100 d1也会改变
Date& operator+=(int day)
{
if (day >= 0)
_day += day;
else
{
//如果输入的day是负数,就去调 operator-=
return *this -= -day; //记得是-day,不然会造成无限循环调用
}
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
++_month;
if (_month > 12)
{
++_year;
_month = 1;
}
}
return *this;
}
//d1 -= 100 d1也会改变
Date& operator-=(int day)
{
if (day >= 0)
_day -= day;
else
{
//如果_day 是负数就去调 operator-=
return *this += -day; //记得是-day,不然会造成无限循环调用
}
while (_day < 1)
{
_day += GetMonthDay(_year, _month);
--_month;
if (_month < 1)
{
--_year;
_month = 12;
}
}
return *this;
}
//d1 + 100 d1不会改变
Date operator+(int day) const
{
Date ret = *this;
ret += day;
return ret; //这里返回的是临时变量,出了作用域会自动销毁,所以不用 Date&
}
//d1 - 100 d1不会改变
Date operator-(int day) const
{
Date ret = *this;
ret -= day;
return ret;
}
//前置++
Date& operator++()
{
return *this += 1;
}
//后置++,为了构成重载所以加了一个int
Date operator++(int)
{
Date tmp = *this;
*this += 1;
return tmp;
}
//前置--
Date& operator--()
{
return *this -= 1;
}
//后置--
Date operator--(int)
{
Date tmp = *this;
*this -= 1;
return tmp;
}
// & 取地址
const Date* operator&() const //后面加const 修饰为 const Date* this
{
return this; //返回的也是const Date* ,如果函数名不加const,返回值类型就变成了 Date* ,不符合
}
void print() //const
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//计算两个日期类对象之间的差值
int operator- (const Date & d)
{
int flag = 1;
Date max = *this;
Date min = d;
if (max < min)
{
max = d;
min = *this;
flag = -1;
}
int n = 0;
while (max != min)
{
++min;
++n;
}
return n * flag;
}
};
int main()
{
Date d1(2020, 4, 15);
//d1 -= -100;
//d1.print();
/*Date d2 = d1 + -100;*/
Date d2 = d1--;
d2.print();
Date d3(2020,4,18);
Date d4(2021,4,18);
cout << d3 - d4 << endl;
return 0;
}