1、
当一个重载的运算符是成员函数时,this绑定到左侧运算对象。成员运算符函数的(显式)参数数量比运算对象的数量少一个。
通常情况下,不应该重载逗号、取地址、逻辑与和逻辑或运算符。
关于重载运算符的返回类型(应与其内置版本的返回类型兼容):
逻辑和关系运算符应该返回bool,算术运算符应该返回一个类类型,赋值运算符和复合赋值运算符应该返回左侧运算对象的一个引用。
关于将运算符定义为成员函数还是普通的非成员函数的抉择:
- 赋值、下标、调用()、成员访问箭头运算符必须是成员。
- 复合赋值一般应为成员,非必须。
- 改变对象状态或者与给定类型密切相关的运算符(如递增、递减、和解引用等),通常为成员。(如 %= 、++)
- 具有对称性的运算符可能转换为任意一端的运算对象(如算术、相等性、关系和位),因此通常应该是普通的非成员函数。
重载与内置运算符的区别:重载必须具有至少一个class或者枚举类型的操作数;重载不保证求值顺序(如短路特性)
相同点:优先级、结合性、操作数的数目都不变。
2、
IO运算符,必须将其定义成非成员函数。IO运算符通常需要读写类的非公有数据成员,IO运算符一般被声明为友元。
3、
如果类同时定义了算术运算符和相关的复合赋值运算符,则通常情况下应该使用复合赋值来实现算术运算符。
4、
赋值运算符
5、
下标运算符:如果一个类包含下标运算符,则它通常会定义两个版本:一个返回普通引用,另一个是类的常量成员并且返回常量引用。
6、
递增和递减运算符:
为了与内置版本保持一致,前置运算符应该返回递增或递减后对象的引用。
后置运算符应该返回对象的原值(递增或递减之前的值),返回的形式是一个值而非引用。
区别前置与后置的方式:后置版本接受一个额外的(不被使用)int类型的形参。若通过函数调用的方式调用后置版本,则必须为它的整形参数传递一个值。
7、
成员访问运算符:
重载的箭头运算符必须返回类的指针或者自定义了箭头运算符的某个类的对象。
8、
函数调用运算符:
lambda是函数对象:默认情况下lambda不能改变它捕获的变量。因此默认情况下,lambda产生的类当中的函数调用运算符是一个const成员函数。若lambda被声明为可变的,则调用运算符就不是const的了。
表示lambda及相应捕获行为的类:引用捕获,值捕获(变量拷贝)
lambda表达式产生的类不含默认构造函数、赋值函数及默认析构函数。是否含有默认的拷贝/移动构造函数则通常要视捕获的数据成员类型而定。
标准库定义的函数对象:
//统计大于1024的值有多少个
count_if(vec.begin(), vec.end(), bind2nd(greater<int>(), 1024));
//找到第一个不等于pooh的字符串
find_if(vec.bein(), vec.end(), bind2nd(not_equal_to<string>(), "pooh"));
//将所有值乘以2
transform(vec.begin(), vec.end(), vec.begin(), bind2nd(multiplies<int>(), 2));
标准库function类型
//简单的桌面计算器 处理int二元运算
#include<iostream>
#include<map>
#include<algorithm>
#include<functional>
using namespace std;
map<string, function<int (int, int)>> binOps = {
{ "+", plus<int>() },
{ "-", minus<int>() },
{ "*", multiplies<int>() },
{ "/", divides<int>() },
{ "%", modulus<int>() }
};
int main()
{
int a, b;
string op;
cin >> a >> op >> b;
cout << binOps[op](a, b) << endl;
return 0;
}
9、重载、类型转换与运算符
类型转换运算符(类的成员函数,无返回类型,无形参): operator type() const
显式的类型转换运算符:如果表达式被用作条件,则编译器会将显式的类型转换自动应用于它。
向bool类型转换通常用在条件部分,因此operator bool一般定义成explicit的。