1 变量之间的赋值
int main()
{
int a = 10;
int b = 20;
a = b;
return 0;
}
2 引入赋值运算重载符
- 调用赋值运算符重载函数:
- 如果一个类没有显式实现赋值运算符重载函数,则编译器会生成一份默认的完成对象之间的赋值操作
int main()
{
Date d0;
Date d1(2020, 10, 12);
Date d2(d1);
Date d3(2020, 10, 13);
d1 = d3;
return 0;
}
完整的代码:
#if 0
class Date
{
public:
// 成员函数在类内实现,编译器可能会将其当成内联函数来处理
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// 拷贝构造函数
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
cout << "Date(Date&):" << this << endl;
}
void PrintDate()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d0;
Date d1(2020, 10, 12);
Date d2(d1);
Date d3(2020, 10, 13);
// 调用赋值运算符重载函数
// 如果一个类没有显式实现赋值运算符重载函数,则编译器会生成一份默认的
// 完成对象之间的赋值操作
d1 = d3;
int a = 10;
int b = 20;
a = b;
return 0;
}
#endif
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
- 函数名字为:关键字operator后面接需要重载的运算符符号。
- 函数原型:返回值类型 operator操作符(参数列表)
3 如果类中涉及到资源管理时,赋值运算符重载函数必须要显式实现出来
#if 0
class String
{
public:
String(const char* str = "")
{
_str = (char*)malloc(strlen(str) + 1);
strcpy(_str, str);
}
String(const String& s)
{
cout << "String(const String& s):" << this << endl;
}
// String类没有实现自己的拷贝构造函数,则编译器会生成一份
~String()
{
if (_str)
{
free(_str);
_str = nullptr;
}
}
private:
char* _str;
};
void TestString()
{
String s1("hello");
String s2("world");
// 调用拷贝构造,构造一个新对象s3
String s3(s2);
// 拷贝构造构造
String s4 = s3;
// 编译器生成的赋值运算符重载是按照浅拷贝的方式实现的
// 如果类中涉及到资源管理时,会导致以下两个后果:
// 存在两个后果:
// 1. 浅拷贝:造成后果一份资源释放多次引起代码崩溃
// 2. s1原来的空间丢失了--内存泄漏
s1 = s2;
}
int main()
{
TestString();
return 0;
}
#endif
注意
不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型或者枚举类型的操作数
用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不能改变其含义
作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的操作符有一个认的形参this,限定为第一个形参
.* 、:: 、sizeof 、?: 、. 注意以上5个运算符不能重载。
class Date
{
public:
// 成员函数在类内实现,编译器可能会将其当成内联函数来处理
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// 拷贝构造函数
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
cout << "Date(Date&):" << this << endl;
}
void PrintDate()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//原先的写法
bool IsLess(const Date& d)
{
if ((_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day))
{
return true;
}
return false;
}
// 针对原始方法优化的赋值运算符函数
// 对于自定义类型,编译器不知道如何进行相应运算符的操作
// 因此需要对该运算符进行重载,相当于告诉编译器针对该中类型的对象如何进行此运算符操作
//<
bool operator<(const Date& d)
{
if ((_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day))
{
return true;
}
return false;
}
// ==
bool operator==(/*Date* const this, */const Date& d)
{
return _year == d._year &&
_month == d._month &&
_day == d._day;
}
//!=
bool operator!=(const Date& d)
{
return !(*this == d);
}
// 注意:不能臆造运算符来进行重载
//void operator@()
//{
//}
//+=
Date& operator+=(int days)
{
//Date temp(*this);
//temp._day += days;
//return temp;
_day += days;
return *this;
}
//+
Date operator+(int days)
{
Date temp(*this);
temp._day += days;
return temp;
}
private:
int _year;
int _month;
int _day;
};
enum Data
{ONE, TWO, THREE};
//死循环,因为自己调用了自己
//int operator+(Data a, int b)
//{
// return a + b;
//}
int main()
{
Date d1(2020, 10, 12);
Date d2(2020, 10, 13);
//变量比较
int a = 10;
int b = 20;
if (a < b)
{
cout << "a < b" << endl;
}
else
{
cout << "a >= b" << endl;
}
//原始方法比较
if (d1.IsLess(d2))
{
cout << "d1 < d2" << endl;
}
else
{
cout << "d1 >= d2" << endl;
}
//写了赋值运算符函数之后比较
if (d1 < d2)
{
cout << "d1 < d2" << endl;
}
else
{
cout << "d1 >= d2" << endl;
}
//!=
if (d1 != d2)
{
cout << "d1 != d2" << endl;
}
else
{
cout << "d1 == d2" << endl;
}
a + 10;
d1 += 10;
d2 = d1 + 2;
return 0;
}
4 易出错地方
int operator+(Data a, int b)
{
return a + b;
}
赋值运算符主要有四点: 参数类型、 返回值、检测是否自己给自己赋值、 返回*this
- 一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝。(按字节拷贝就是原封不动的拷贝过去,其实就是浅拷贝)
往期链接:
cpp_9.2类和对象中(八) — 拷贝构造函数
cpp_9.1 类和对象中(七)—构造函数中,无参对象如何调用?底层如何实现?
cpp_8.2类和对象中(六) — 析构函数
cpp_8.1类和对象中(五) — 构造函数链接描述
cpp_8 类和对象上(四) — this遗留
cpp_7.1 类和对象上(三) — this
cpp_7类与对象上(二) — 类对象的存储方式
cpp_6.1类与对象上(一)— 类的引入