目录
导读
前面我们学习了默认成员函数:构造函数、析构函数和拷贝构造函数。
今天我们来学习赋值运算符重载。
1. 为什么需要运算符重载
我们一般的运算符只能对于数字进行运算,或是比较大小,但是如果我们想要对我们所定义的自定义类型进行运算呢?
为了使自定义类型能够支持运算符操作,可以通过运算符重载的方式来重新定义这些运算符,使其能够在自定义类型上执行特定的操作。
比如我们定义了一个日期类,想要对这个日期类进行加减运算,亦或是比较两个日期的大小,通过运算符重载即可实现。
2. 运算符重载概念
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其 返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
一般来说需要遵循以下几个原则:
-
运算符的重载必须定义在类、结构体或枚举中。
-
运算符重载函数必须使用特殊的命名约定,以指示要重载的运算符。
-
运算符重载函数可以是类的成员函数,也可以是非成员函数。
-
运算符重载函数的参数和返回值类型应该与运算符原有的操作数类型相匹配。
-
运算符重载函数可以使用其他的运算符或已有的函数来实现其操作。
3. 运算符重载示例
3.1 == 运算符重载
我们来判断两个日期是否相等:
我们需要依次比较年、月、日。
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//operator运算符 做函数名
bool operator == (const Date& y)
{
return _year == y._year
&& _month == y._month
&& _day == y._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2024, 2, 02);
Date d2(2024, 2, 03);
cout << d1.operator == (d2) << endl;
return 0;
}
我们知道,运算符重载也是默认成员函数之一,也就是我们不去调用,编译器也会自动帮我们调用。
比如:
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//operator运算符 做函数名
bool operator == (const Date& y)
{
return _year == y._year
&& _month == y._month
&& _day == y._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2024, 2, 3);
Date d2(2024, 2, 2);
cout << d1.operator == (d2) << endl;
cout << (d1 == d2) << endl;
return 0;
}
3.2 >或<运算符
判断两个日期的大小:
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//operator运算符 做函数名
bool operator < (const Date& y)
{
if (_year < y._year)
{
return true;
}
else if (_year == y._year)
{
if (_month < y._month)
{
return true;
}
else if (_month == y._month)
{
return _day < y._day;
}
}
return false;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2024, 1, 28);
Date d2(2024, 1, 29);
cout << d1.operator < (d2) << endl;
cout << (d1 < d2) << endl;
return 0;
}
4. 运算符重载参数
上述我们的代码明明是对两个日期进行比较,为何只有一个参数呢?
运算符重载函数的参数取决于要重载的运算符的操作数个数和类型。
-
一元运算符重载:一元运算符只有一个操作数。在重载一元运算符时,通常将其定义为类的成员函数,没有参数(除了隐式的this指针)。
-
二元运算符重载:二元运算符有两个操作数。在重载二元运算符时,可以选择将其定义为类的成员函数或非成员函数。
-
如果将二元运算符定义为类的成员函数,参数列表将包括一个额外的参数,表示右侧操作数。左侧操作数则是隐式的this指针。
-
如果将二元运算符定义为非成员函数(全局函数或友元函数),参数列表将包括两个参数,分别表示左侧和右侧操作数。
-
5. 全局运算符重载函数
我们依旧对比两个日期是否相等,判断大小,注意与上述代码的参数差异。
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//private:
int _year;
int _month;
int _day;
};
//operator运算符 做函数名
bool operator == (const Date& x, const Date& y)
{
return x._year == y._year
&& x._month == y._month
&& x._day == y._day;
}
bool operator < (const Date& x, const Date& y)
{
if (x._year < y._year)
{
return true;
}
else if (x._year == y._year)
{
if (x._month < y._month)
{
return true;
}
else if (x._month == y._month)
{
return x._day < y._day;
}
}
return false;
}
int main()
{
Date d1(2024, 1, 28);
Date d2(2024, 1, 29);
cout << operator == (d1, d2) << endl;
cout << operator < (d1, d2) << endl;
cout << (d1 == d2) << endl;
cout << (d1 < d2) << endl;
return 0;
}
6. 赋值运算符重载
6.1 语法及概念
赋值运算符重载是一种特殊的运算符重载,用于在自定义的类中重载"="运算符,使其能够对类对象进行正确的赋值操作。
赋值运算符重载的语法如下:
class ClassName {
public:
ClassName& operator=(const ClassName& other) {
// 执行赋值操作的代码
return *this;
}
};
在赋值运算符重载函数中,通常需要执行以下操作:
-
检查是否是自我赋值,即当前对象和要赋值的对象是否是同一个对象。如果是同一个对象,则直接返回当前对象,避免不必要的操作。
-
进行属性的深拷贝,将要赋值的对象的属性逐个复制给当前对象的属性。
-
返回当前对象的引用。
6.2 示例
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << '/' << _month << '/' << _day << endl;
}
Date& operator=(const Date& d)
{
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2024, 2, 01);
Date d2(2024, 2, 02);
Date d3(2024, 2, 03);
d1 = d2 = d3;
d1.Print();
d2.Print();
d3.Print();
return 0;
}
6.3 为何使用引用
-
引用参数:赋值运算符需要修改当前对象的值,而不是创建一个新的对象。因此,使用引用参数,可以直接修改当前对象而不是在函数内部创建一个副本。
-
返回this指针:赋值运算符一般返回当前对象的引用,即*this。这样可以实现连续赋值操作,例如 a = b = c。通过返回this指针,可以链式调用赋值运算符。