运算符重载
为用户定义类型的操作数定制C++运算符。
语法
重载运算符是具有特殊函数名称的函数。
1 | operator | op | ||
2 | operator | type | ||
3 | operator new operator new [] | |||
4 | operator delete operator delete [] | |||
5 | operator "" | suffix-identifier | (自 C++11 起) | |
6 | operator co_await | (自 C++20 起) |
pub | op | 以下任意运算符:+ - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= <=> (自 C++20 起) && || ++ -- , ->* -> ( ) [ ] |
- 重载运算符;
- 用户定义的转换函数;
- 分配函数;
- 释放函数;
- 用户定义的字面量;
- 用于co_await 表达式的重载 co_await 运算符。
重载运算符
当运算符出现在表达式中,并且至少有一个操作数具有类类型或枚举类型时,将使用重载解析来确定要调用的用户定义函数,该函数是所有签名符合以下条件的函数。
表达式 | 作为成员函数 | 作为非成员函数 | 示例 |
---|---|---|---|
@a | (a).operator@ ( ) | operator@ (a) | !std::cin 调用 std::cin.operator!() 。 |
a@b | (a).operator@ (b) | operator@ (a, b) | std::cout << 42 调用 std::cout.operator<<(42) 。 |
a=b | (a).operator= (b) | 不能是非成员 | 给定 std::string s; ,s = "abc"; 调用 s.operator=("abc") 。 |
a(b...) | (a).operator()(b...) | 不能是非成员 | 给定 std::random_device r; ,auto n = r(); 调用 r.operator()() 。 |
a[b...] | (a).operator | 不能是非成员 | 给定 std::map<int, int> m; ,m[1] = 2; 调用 m.operator[](1) 。 |
a-> | (a).operator-> ( ) | 不能是非成员 | 给定 std::unique_ptr<S> p; ,p->bar(); 调用 p.operator->() 。 |
a@ | (a).operator@ (0) | operator@ (a, 0) | 给定 std::vector<int>::iterator i; ,i++ 调用 i.operator++(0) 。 |
在此表中,@ 是一个占位符,代表所有匹配的运算符:@a 中的所有前缀运算符,a@ 中的除 -> 之外的所有后缀运算符,a@b 中的除 = 之外的所有中缀运算符。 |
==
、!=
、<
、>
、<=
、>=
、<=>
,重载解析还会考虑由 operator==
或 operator<=>
生成的*重写候选*。 (自 C++20 起)
注意:有关重载 co_await (自 C++20 起)、用户定义的转换函数、用户定义的字面量、分配和释放,请参阅各自的文章。
重载运算符(但不是内置运算符)可以使用函数表示法调用。
std::string str = "Hello, ";
str.operator+=("world"); // same as str += "world";
operator<<(operator<<(std::cout, str), '\n'); // same as std::cout << str << '\n'
// (since C++17) except for sequencing
限制
- 无法重载以下运算符:
::
(作用域解析)、.
(成员访问)、.*
(指向成员的指针进行成员访问) 和?:
(三元条件)。 - 无法创建新运算符,例如
**
、<>
或&|
。 - 无法更改运算符的优先级、分组或操作数数量。
- 运算符
->
的重载必须返回原始指针,或者返回一个其自身运算符->
也被重载的对象(通过引用或值)。 - 运算符
&&
和||
的重载会丢失短路求值。 -
当重载
&&
、||
和,
(逗号) 运算符时,它们会失去其特殊的排序属性,即使它们在不使用函数调用表示法时也像常规函数调用一样工作。 (C++17 之前)