【c++运算符重载】

c++运算符重载

    • 基本概念
      • 调用方式
      • 某些运算符不应该被重载
      • 使用与内置类型一致的含义
      • 选择作为成员或者非成员
    • 输入和输出运算符
      • 重载输出运算符 <<
      • 重载输入运算符 >>
    • 算数和关系运算符
      • 相等运算符
      • 关系运算符
    • 赋值运算符
    • 下标运算符
    • 递增和递减运算符
    • 函数调用运算符
      • lambda是函数对象

常忘常看,记录下来以备后忘

基本概念

关键字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是函数对象

你可能感兴趣的:(C++,c++)