第十四章 重载运算与类型转换

第十四章 重载运算与类型转换

重载运算符名字由operator和其后要定义的运算符号共同组成。 一元运算符有一个参数,二元运算符有两个参数,如果是类成员函数,则有一个隐式参数,显式参数要少一个。

规则

  • 不应该被重载: 无法保留求值顺序(& | ,) ; 无法保留短路求值属性(&& ||);还有逗号和取地址符(, &)
  • 如果有operator == 也应该有 operator != , 并且两者可以互相委托,只要定义一个即可。
  • 返回类型: 逻辑运算符和关系运算符返回bool , 算术运算符返回类类型 ,赋值运算符和复合赋值运算符返回左侧运算对象类型的引用, 输入输出运算符返回流对象的引用
  • 作为类成员还是非成员:
    • 必须是成员: 赋值 (=) 、下标( [] ) 、 调用( () )、和成员访问箭头( -> )
    • 应该是成员: 改变对象状态的运算符或者与给定类型相关的运算符。 ( ++ ) ( – ) ( * 解引用) (+= 复合赋值运算符)
    • 应该是非成员: 具有对称性的运算符 (可能会发生类型转换。如果定义为成员,则对于运算符左右两侧对象的类型有较大的限制)

实例

输入运算符

  • 必须定义为非成员类型
  • 第一个形参是 非常量ostream类型的引用 , 第二个形参是常量的引用; 返回它的ostream形参。
  • 输出运算符要尽量减少格式化操作。

输入运算符

  • 必须定义为非成员类型,且必须处理输入可能失败的情况
    • 输入失败 1. 输入类型错误 2.文件结尾或者输入流错误。
    • 如果发生错误,一般将对象置于默认状态(合法)
  • 应该设置流的条件状态标示错误信息。

算术和关系运算符

  • 一般定义为非成员函数 (方便类型转换) , 形参都是常量引用
  • 返回类型一般是左侧对象类型的引用。
  • 使用….复合赋值来定义算术运算符 (如果要同时定义两者)

相等运算符

  • 定义为非成员函数
  • 会比较对象的每个数据成员,完全一致才会认为两个对象相等。
  • 定义了== 也要定义!= , return !(A==B); 即可。

关系运算符

  • 一般定义operator < 比较有用。 还可以用于关联容器。

  • 准则: 1. 满足通常意义上的“小于” 2.如果类存在!=运算符, 一个类对象!=另一个对象 ,则这两个对象应该有<关系。 如果没有,则不应定义 < 操作符(不存在一种逻辑可靠的小于运算)。

赋值运算符

  • 主要用于不同类型之间的赋值。返回类型是左侧运算对象的引用
  • 赋值运算符必须先释放当前内存空间,再创建一片新空间。
复合赋值运算符
  • 倾向于定义在类的内部。 返回类型是左侧对象类型的引用。

下标运算符

  • 必须是成员函数; 参数一般是size_t 类型。
  • 返回值是 所访问的元素的引用。 (可用作左值使用)

递增递减运算符

  • 因为改变了对象的状态,所以倾向于定义在类内部。
  • 前置++/– : operator ++(); 后置++/–: operator -- (int);
    • 后置版本接受一个额外的int类型的形参。
    • 并不会使用这个形参,唯一作用就是区分前置和后置版本。
  • 后置版本应返回对象的原值(递增或递减之前的值),返回类型是值而不是引用。
  • 显示调用: p.operator++(0); //后置版本 , p.operator--();//前置版本

成员访问运算符

解引用运算符(* )
  • 通常是类的成员
  • 返回类型视元素类型而定。 返回引用,可以用作左值。
箭头运算符(->)
  • 必须是类的成员
  • 调用解引用运算符… 返回指向要访问对象的指针(函数指针,可以直接调用使用) return & this->operator *(); // &是取地址符。
  • 重载的箭头运算符必须返回类的指针或者自定义了箭头运算符的某个类的对象。

函数调用运算符

  • 必须是成员函数 , 能像使用函数一样使用类的对象。
  • 并且可以 存储状态!
  • lambda : 未命名类的未命名对象(重载了函数调用运算符)。如果使用值捕获,还会创建对应类型的数据成员以及构造函数(如果显式使用这个类,必须提供一个实参)。
标准库定义的函数对象
  • plus ; // +

  • modulus ; // %

  • equal_to ; // ==

  • 定义在头文件中

  • 用法: sort(vec.begin(),vec.end(), greater<string>()); //使用greater模板string实例来代替原来的" < " //运算符,使元素按 > 排列。

  • 算术关系逻辑
    plusequal_tological_and
    minusnot_equal_tological_or
    multipliesgreaterlogical_not
    dividesgreater_equal
    modulusless
    negateless_equal
可调用对象与function
  • 可调用对象: 函数、函数指针、lambda表达式、bind创建的对象、重载了函数调用运算符的类。
  • 调用形式: 返回类型,实参类型。
  • 标准库function类型:
    • function<int (int,int) >; 是一个function类型,可以表示接受两个int参数,返回一个int参数的可调用对象。
    • 所有可调用对象,包括函数指针 lambda 或者函数对象 都可以用function类型表示。
    • 创建一个map<string, function < int (int ,int )> > binops;map操作集合,可以 通过下标运算符访问对应的操作。
    • 不能直接将重载函数的名字存入function类型的对象,必须通过指针形式加以区分,或者通过lambda重写。

重载、类型转换与运算符

通过定义类型转换运算符,将实参类型的对象转换成类类型

类类型转换运算符
  • operator type() const ;
  • 类类型转换函数必须是类的成员函数; 不能声明返回类型; 形参列表为空;通常应该是const。
  • 类型转换运算符是隐式执行的。
  • 显式的类型转换运算符: explicit operator int () const {return val ; }
  • eg: while(std::cin >> value) cin被istream operator bool类型转换函数隐式转换(即使它是explicit的), 如果cin的条件状态是good, 则隐式转换为true, 否则转换为false。
    • 在if ,while , do语句的条件部分; for语句头的条件表达式, ! 、 || 、 &&的运算对象或者 ?: 的条件表达式中,explicit的类型转换运算符也会被隐式执行。
类型转换二义性
  • 当从B转换到A有多种方式时,就会出现二义性。并且无法使用强制类型转换来解决二义性问题(此时强制类型转换也有二义性)。
  • 解决: 不要为类定义相同的类型转换,也不要在类中定义两个及两个以上转换源或者目标是算数类型的转换规则。 除了显式向bool类型转换,要避免定义其他类型转换函数。
  • 只有当重载函数能通过同一个类型转换函数得到匹配时 才会考虑标准类型转换哪个优先的问题。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值