重载比较运算符
本节阅读量:
比较运算符一共有六个。重载这些比较运算符相对简单,因为它们遵循与其他运算符重载相同的模式。
由于比较运算符都是不修改左操作数的二元运算符,因此我们通常将它们重载为友元函数。
下面是一个Car类示例,它重载了运算符==和运算符!=。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
#include <iostream>
#include <string>
#include <string_view>
class Car
{
private:
std::string m_make;
std::string m_model;
public:
Car(std::string_view make, std::string_view model)
: m_make{ make }, m_model{ model }
{
}
friend bool operator== (const Car& c1, const Car& c2);
friend bool operator!= (const Car& c1, const Car& c2);
};
bool operator== (const Car& c1, const Car& c2)
{
return (c1.m_make == c2.m_make &&
c1.m_model == c2.m_model);
}
bool operator!= (const Car& c1, const Car& c2)
{
return (c1.m_make != c2.m_make ||
c1.m_model != c2.m_model);
}
int main()
{
Car corolla{ "Toyota", "Corolla" };
Car camry{ "Toyota", "Camry" };
if (corolla == camry)
std::cout << "a Corolla and Camry are the same.\n";
if (corolla != camry)
std::cout << "a Corolla and Camry are not the same.\n";
return 0;
}
|
这里的代码应该很简单。
operator<和operator>呢?一辆车比另一辆车“大”或“小”意味着什么?通常并没有这样的关系。由于运算符<和运算符>的结果并不直观,因此这里最好不要定义这些运算符。
然而,上述建议也有例外。如果我们想对汽车列表进行排序,该怎么办?在这种情况下,我们可能希望重载比较运算符,使其按照最符合预期的方式排序。例如,重载运算符<后,汽车可以根据品牌和型号按字母顺序排序。
标准库中的一些容器类(保存其他对象的类)需要元素重载运算符<,以便对元素进行排序。
下面是另一个重载所有6个逻辑比较运算符的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
#include <iostream>
class Cents
{
private:
int m_cents;
public:
Cents(int cents)
: m_cents{ cents }
{}
friend bool operator== (const Cents& c1, const Cents& c2);
friend bool operator!= (const Cents& c1, const Cents& c2);
friend bool operator< (const Cents& c1, const Cents& c2);
friend bool operator> (const Cents& c1, const Cents& c2);
friend bool operator<= (const Cents& c1, const Cents& c2);
friend bool operator>= (const Cents& c1, const Cents& c2);
};
bool operator== (const Cents& c1, const Cents& c2)
{
return c1.m_cents == c2.m_cents;
}
bool operator!= (const Cents& c1, const Cents& c2)
{
return c1.m_cents != c2.m_cents;
}
bool operator> (const Cents& c1, const Cents& c2)
{
return c1.m_cents > c2.m_cents;
}
bool operator< (const Cents& c1, const Cents& c2)
{
return c1.m_cents < c2.m_cents;
}
bool operator<= (const Cents& c1, const Cents& c2)
{
return c1.m_cents <= c2.m_cents;
}
bool operator>= (const Cents& c1, const Cents& c2)
{
return c1.m_cents >= c2.m_cents;
}
int main()
{
Cents dime{ 10 };
Cents nickel{ 5 };
if (nickel > dime)
std::cout << "a nickel is greater than a dime.\n";
if (nickel >= dime)
std::cout << "a nickel is greater than or equal to a dime.\n";
if (nickel < dime)
std::cout << "a dime is greater than a nickel.\n";
if (nickel <= dime)
std::cout << "a dime is greater than or equal to a nickel.\n";
if (nickel == dime)
std::cout << "a dime is equal to a nickel.\n";
if (nickel != dime)
std::cout << "a dime is not equal to a nickel.\n";
return 0;
}
|
这也相当简单。
最大限度地减少相对冗余
在上面的示例中,请注意每个重载比较运算符的实现有多相似。重载比较运算符往往高度冗余,实现越复杂,冗余就越多。
幸运的是,许多比较运算符可以使用其他比较运算符来实现:
- 运算符!= 可以实现为 !(运算符==)
- 运算符> 可以实现为 运算符<,只要参数的顺序翻转
- 运算符>= 可以实现为 !(运算符<)
- 运算符<= 可以实现为 !(运算符>)
这意味着我们只需要实现运算符==和运算符<的逻辑,然后就可以根据这两个运算符定义其他四个比较运算符!下面是更新后的Cents示例,说明了这一点:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#include <iostream>
class Cents
{
private:
int m_cents;
public:
Cents(int cents)
: m_cents{ cents }
{}
friend bool operator== (const Cents& c1, const Cents& c2) { return c1.m_cents == c2.m_cents; }
friend bool operator!= (const Cents& c1, const Cents& c2) { return !(operator==(c1, c2)); }
friend bool operator< (const Cents& c1, const Cents& c2) { return c1.m_cents < c2.m_cents; }
friend bool operator> (const Cents& c1, const Cents& c2) { return operator<(c2, c1); }
friend bool operator<= (const Cents& c1, const Cents& c2) { return !(operator>(c1, c2)); }
friend bool operator>= (const Cents& c1, const Cents& c2) { return !(operator<(c1, c2)); }
};
int main()
{
Cents dime{ 10 };
Cents nickel{ 5 };
if (nickel > dime)
std::cout << "a nickel is greater than a dime.\n";
if (nickel >= dime)
std::cout << "a nickel is greater than or equal to a dime.\n";
if (nickel < dime)
std::cout << "a dime is greater than a nickel.\n";
if (nickel <= dime)
std::cout << "a dime is greater than or equal to a nickel.\n";
if (nickel == dime)
std::cout << "a dime is equal to a nickel.\n";
if (nickel != dime)
std::cout << "a dime is not equal to a nickel.\n";
return 0;
}
|
这样,如果以后需要更改比较逻辑,只需要更新operator==和operator<,而不必修改所有六个比较运算符!
太空船 运算符<=> (C++20)
C++20引入了太空船运算符(operator<=>),它可以将需要编写的比较函数数量减少到最多2个,有时甚至只需要1个。我们会在后续某一课中讨论它!