常忘常看,记录下来以备后忘
基本概念
关键字operator和其后要定义的运算符号共同组成。除了operator()之外,其他不能重载运算符不能有默认参数。 一元运算符只传递一个参数,二元运算符传递两个参数给函数。 一个运算符函数是成员函数,this绑定到左侧运算对象,所以成员运算符(显式)参数数量比运算对象少一个
note: 内置类型不可以重载运算符,且只能重载已有运算符,不能被重载的运算符包括 :: .* . ?:
调用方式
直接用运算符或者直接调用函数 data1 + data2 ,也可以operator(data1, data2) 成员函数时也可以写成data1+= data2 data1.opterator+(data2),其中+= 这个二元操作符的第一个参数是隐式传入的data1
某些运算符不应该被重载
& , 等运算符是有特殊意义的,不建议重载 本质上运算符重载是一次函数调用,所以无法保留求值顺序 短路求值属性,所以不建议重载
使用与内置类型一致的含义
设计类时,考虑类将提供哪些操作,之后再思考把类设成普通函数还是重载的运算符。
- 如果类执行I/O,定义移位运算符与其内置IO保持一致
- 检查相等性,用operator==,有了这个通常也应该有,operator !=
- 类包含一个内在单序比较,定义operator < ,通常应该定义其他关系操作
- 返回类型也应该与其内置版本兼容。逻辑和关系返回bool,算数运算符返回类类型的值,赋值和符合运算符应该返回运算对象的一个引用
- 赋值和复合赋值运算符:返回左侧对象的一个引用
选择作为成员或者非成员
某些时候必须作为成员,但是有些情况,普通函数比成员更好。
- = []以及调用运算符() 以及 -> 必须是成员函数
- 复合赋值类的一般是成员
- 改变对象状态的++ --等 ,通常是成员
- 具有对称性的,通常应该是非成员
输入和输出运算符
重载输出运算符 <<
通常情况下,第一个参数应该是非常量ostream对象的引用。非常量是因为会改变对象状态,引用是因为ostream对象无法复制 输出运算符应该尽量减少格式化操作,尤其不会打印换行符 通常情况下,它应该主要负责输出内容而非格式 **输入输出运算符必须是非成员函数,否则左侧对象将是我们类的一个对象,我们的格式将会变成data << out。。**如果定义成正常输出方式,我们又无法有来看中stream成员增加函数
所以我们要将输入输出定义成非成员函数,当然因为我们要读写类的非公有数据成员,所以一般要声明为友元
重载输入运算符 >>
通常第一个参数是读取流的引用,第二个参数是非常量的对象的引用,返回值是给定流的引用。
istream & operator >> (istream& is, Data& data)
{
double price;
is >> data.no >> data.sold >> price;
if(is)
{
data.revenue = data.sold * price;
}
else
{
data = Data();
}
}
注意:输入运算符必须处理可能失败的情况
算数和关系运算符
一般会定义成非成员函数,因为一般不需用改变运算对象的状态,所以形参都是常量的引用。
相等运算符
如果一个类含有两个对象比较相等的操作,应该定义operator== ,因为符合用户习惯 定义了opterator== , 运算符应该能判定一组给定对象中是否含有重复数据 通常情况下,相等运算符应该有传递性 如果定义了operator==,也应该定义operator != operator==,operator != 应该一个运算符委托给另外一个去做,比如,operator != 中返回 ! operator== 的操作
本内容参照c++ primer第四版内容
关系运算符
定义了==的通常也会定义小于运算符,因为关联容器和一些算法需要用到小于运算符,所以定义<比较有用
赋值运算符
和拷贝赋值以及移动赋值一样,重载的赋值函数,应当先释放当前内存空间,然后再创建一片新空间。
下标运算符
必须是成员函数,通常会定义两个版本,一个是返回普通引用,一个返回类的常量成员并返回常量引用
递增和递减运算符
前置operator++() 后置operater++(int) 参数仅用来区分前置后置运算符
函数调用运算符
如果重载了函数调用运算符(),则可以想使用函数一样,使用该类的对象
struct abrInt
{
int operator()(int) const
{
return val < 0 ? -val : val;
}
}
int i = 19;
abrInt absObj;
absObj(i);
如果类定义了调用运算符,该类对象称为函数对象。即使absObj只是一个对象,也能"调用"该对象。实际上是调用重载的调用运算符。
lambda是函数对象
|