当前课程知识点:基于Linux的C++ > 第十讲 操作符重载 > 10.4 关系与下标操作符重载 > LinuxCPP1004
接下来是关系操作符的重载
我们可以在这个数偶类上面
替它定义关系操作符
我们的关系操作符当然不是这两个了
其实关系操作符总共是6个
什么大于、不大于、小于、不小于、
然后等于、不等于 对吧
这6个操作符 都可以被重载
我们这里边只以等于和不等于为例
我们来看怎么在数偶类上
重载关系操作符
在数偶类上重载我们关系操作符的时候
这样的关系操作符
也应该重载为类的友元函数
传递双参数 c1、c2
当然 这两个参数同样是
对constCouple类的引用
我们判定这两个数偶对象
是否相等的方式特别简单
就看第一个字段和第一个字段是不是相等
且第二个字段和第二个字段是不是相等
当这两个字段都相等的时候
我们就认为这两个数偶对象是相等的
当它们两个字段中有一个字段不等的时候
我们就认为这两个数偶对象它们是不等的
很简单 所以我们就return(c.a==c2.a)&&(c1.b==c2.b)
前面是逻辑与 后面就是逻辑或
实现上多简单呐
就那么一条语句 我们就把它搞定了
这就是关系操作符的重载
有了重载的关系操作符
当你定义了这个Couple类的两个对象
a和b之后 你构造完成了
然后就可以按照普通的关系操作符的
那个访问方式去进行操作
第三个 下标操作符的重载
这个下标操作符有一点点小特殊
什么时候需要重载我们这个下标操作符呢
有一点同学们要特别记住
如果这个类
它具有一个特定的数组成员
并且这个类中的对象
总是频繁地访问这样一个数组成员
而且这个数组成员
是这个类中的主要成员
那么你就可以重载这个下标操作符
你可以不重载 这个没关系
重载下标操作符以后有什么好处呢
好处就是对于这个类的使用者来讲
他就可以把这个类的一个对象
当做一个数组的名字一样
使用下标操作符
访问你想让它访问的
那个主要的数组成员中的
某个特定的元素
它是这样的一个目的 就是允许在对象上
通过数组下标的方式
访问数组成员的对应那个元素
这就是我们重载下标操作符的
最主要的目的
所以同学们要特别记得
如果你要重载这个下标操作符
你一定就要注意
这个类上一定会有一个数组成员
或者类似的起到数组功能的一个成员
而且最重要的
这个成员是这个类的主要成分
大部分操作都是集中在
数组或者类似数组的成员上
这个时候才需要重载它的下标操作符
除此之外 不要重载我们的下标操作符
下标操作符必须重载两个版本
同学们要记住这一点
你重载其中一个版本是不行的
为什么呢 因为我们的那个对象
我们的那个数组成员
可能是个常数 也可能是一个非常数
两者操作的模式是不一样的
非常数 我们可以修改数组元素的值
常数 我们就不能够修改那个数组元素的值
这两者的语义是完全不同的
所以当你提供这个函数的时候
当你提供这个重载的下标操作符的时候
你一定要提供两个版本
常函数的版本用于处理我们的常量
特别要注意这一点
重载下标操作符 当然会有一个额外的好处
它能够允许你对这个数组的下标
是不是越界 进行一些额外的检查
能够防止数组下标越界错误
这种时候有可能
使用我们的异常处理机制
我们来看这个数偶类的
下标操作符的重载的方法
定义两个操作符函数 一个int& operator[]
[]就是我们下标操作符
括号里面传int index
这个是它的那个下标索引
这就是operator[]
这是第一个非常量的版本
第二个就是const int & operator [](int index) const
这是常函数的版本
我们提供这两个版本 每一个都需要
当它是常函数的时候 返回的是constint&
当它是非常函数的时候 返回的是int&
返回的就是数组元素的引用
对于第一个非常函数的版本
那么当它返回那个引用的时候
实际上你就可以通过这个函数的返回值
修改那个引用
所访问的那个目标数据对象
引用所引用的是哪个目标数据对象
当然是这个数组中对应的那个元素啦
所以我们在这个类Couple上边
我们实现的时候
为了适应数组这个方面的变化
把它重写成只包含两个元素的一个数组
而不是像刚才分别定义的两个数据成员
实际上定义两个数据成员
也可以像数组一样访问 这倒关系不大
待会儿我们再解释 我们看实现
对第一个非常函数的版本
我们直接就return _a[index]
index相当于它的索引嘛
就是它的数组元素下标嘛
我就直接返回_a[index]就完了
对于非常函数的版本
也是这样 就返回_a[index]
如果你不考虑数组元素的下标
是不是越界这样一个错误处理的问题
这段代码其实就那么一行 超简单
但是我们这里面实际上在返回这个值之前
要处理这个index下标是不是越界的问题
我们这个数组包括几个元素呢 两个元素
下标是几呢 0或1
只要不是0或1 元素下标就不对
所以if(index<0 || index > 1) 元素下标越界
在这里你就可以输出一个错误的消息
然后程序退出 可以
但是我们这里是使用了异常处理机制
throw std::out_of_range( “Index is out of range!” )
throw是C++给我们提供的异常处理机制
它将引发一个异常 std::out_of_range
这是C++标准库里面替我们定义好的
一个异常类
名字就叫out_of_range
数组下标越界的异常类
它会触发一个异常的信息
我们就可以传递这个异常的信息
构造一个out_of_range类的一个对象
然后把这个对象抛出来
具体的异常处理机制
我们下一讲再详细讨论它
现在同学们只要记住
下标越界的时候
我们可以触发像这样的一个异常
这样就保证了我们的程序
在正常运行状态下
是不会产生数组下标越界错误的
我有了这个下标操作符的重载之后
我就可以定义Couple类的两个对象a、b
然后cin>> a[0] >> a[1]
就按照这个方式把这些数据流进去了
a[0]是什么 就这个数组的0号元
a[1]是什么呢 就是那个数组的1号元啊
它是个int& 当然就可以cin>> a[0]
没有问题 cout一样的
我们就可以直接地像数组一样
操纵这个类的一个对象 方便吧
数组下标操作
重载以后的好处就体现这个地方
它就像一个数组 明明是一个对象
但看上去就像一个数组一样
所以说呢 如果这个对象被你构造出来以后
它的主要行为就是一个数组
其实你就应该提供一个下标操作符
如果它的主要行为不是一个数组
那么其实你不应该提供那个下标操作符
因为你会让这个类库的使用者
误以为它是一个数组
但其实大部分时候都不应该是数组 对吧
所以下标操作符
不是必须要存在的操作符
回到我刚才留的那个问题
当时就是说 如果这个字段
它不是一个数组
难道我们就不能够重载它的下标操作符了
那当然不是
如果是int_a, _b这个模式
定义的那两个数据成员 其实也可以
if(index==0) return _a; else if(index==1) return _b;
else throw std::out_of_range()
OK 也可以 对于我们来说无所谓
传哪一个下标给我
然后我就返回一个
对应的数据成员就行了
不管那个数据成员叫什么名字
它是不是真正的数组的元素
那不重要
重要的是我们能够通过这个方式
“[]”重载的方式让类库的使用者
以一个和数组相一致的方式
来访问我们这个类中的数据成员
达到这个目标就够了
这个就是我们的下标操作符的重载
-1.1 提纲
-1.2 程序设计的基本概念
-1.3 简单C/C++程序介绍
-1.4 程序设计的基本流程
-1.5 基本语法元素
-1.6 程序设计风格
-1.7 编程实践
-第一讲 C/C++基本语法元素--编程实践提交入口
-2.1 提纲
-2.2 结构化程序设计基础
-2.3 布尔数据
-2.4 分支结构
-2.5 break语句
-2.6 循环结构
-2.7 编程实践
-第二讲 程序控制结构--编程实践提交入口
-3.1 提纲
-3.2 函数声明、调用与定义
-3.3 函数调用栈框架
-3.4 编程实践
-第三讲 函数--编程实践提交入口
-4.1 提纲
-4.2 算法概念与特征
-4.3 算法描述
-4.4 算法设计与实现
-4.5 递归算法(一)
-4.6 递归算法(二)
-4.7 容错与计算复杂度
-4.8 编程实践
-第四讲 算法--编程实践提交入口
-5.1 提纲
-5.2 库与接口
-5.3 随机数库(一)
-5.4 随机数库(二)
-5.5 作用域与生存期
-5.6 典型软件开发流程(一)
-5.7 典型软件开发流程(二)
-5.8 编程实践
-第五讲 程序组织与开发方法--编程实践提交入口
-6.1 提纲
-6.2 字符
-6.3 数组(一)
-6.4 数组(二)
-6.5 结构体
-6.6 编程实践
-第六讲 复合数据类型--编程实践提交入口
-7.1 提纲
-7.2 指针基本概念
-7.3 指针与函数
-7.4 指针与复合数据类型(一)
-7.5 指针与复合数据类型(二)
-7.6 字符串
-7.7 动态存储管理(一)
-7.8 动态存储管理(二)
-7.9 引用
-7.10 编程实践
-第七讲 指针与引用--编程实践提交入口
-8.1 提纲
-8.2 数据抽象(一)
-8.3 数据抽象(二)
-8.4 链表(一)
-8.5 链表(二)
-8.6 链表(三)
-8.7 链表(四)
-8.8 函数指针(一)
-8.9 函数指针(二)
-8.10 抽象链表(一)
-8.11 抽象链表(二)
-8.12 编程实践
-第八讲 链表与程序抽象--编程实践提交入口
-9.1 提纲
-9.2 程序抽象与面向对象
-9.3 类类型
-9.4 对象(一)
-9.5 对象(二)
-9.6 类与对象的成员(一)
-9.7 类与对象的成员(二)
-9.8 类与对象的成员(三)
-9.9 继承(一)
-9.10 继承(二)
-9.11 继承(三)
-9.12 多态(一)
-9.13 多态(二)
-9.14 编程实践
-第九讲 类与对象--编程实践提交入口
-10.1 提纲
-10.2 四则运算符重载(一)
-10.3 四则运算符重载(二)
-10.4 关系与下标操作符重载
-10.5 赋值操作符重载(一)
-10.6 赋值操作符重载(二)
-10.7 赋值操作符重载(三)
-10.8 赋值操作符重载(四)
-10.9 赋值操作符重载(五)
-10.10 流操作符重载(一)
-10.11 流操作符重载(二)
-10.12 流操作符重载(三)
-10.13 操作符重载总结
-10.14 编程实践
-第十讲 操作符重载--编程实践提交入口
-11.1 提纲
-11.2 泛型编程概览
-11.3 异常处理机制(一)
-11.4 异常处理机制(二)
-11.5 运行期型式信息(一)
-11.6 运行期型式信息(二)
-11.7 模板与型式参数化
-11.8 题外话:术语翻译
-11.9 泛型编程实践(一)
-11.10 泛型编程实践(二)
-11.11 泛型编程实践(三)
-11.12 泛型编程实践(四)
-11.13 泛型编程实践(五)
-11.14 泛型编程实践(六)
-11.15 泛型编程实践(七)
-11.16 泛型编程实践(八)
-11.17 泛型编程实践(九)
-11.18 泛型编程实践(十)
-11.19 编程实践
-第十一讲 泛型编程--编程实践提交入口
-12.1 提纲
-12.2 程序执行环境(一)
-12.3 程序执行环境(二)
-12.4 程序执行环境(三)
-12.5 程序执行环境(四)
-12.6 输入输出(一)
-12.7 输入输出(二)
-12.8 文件系统
-12.9 设备
-12.10 库(一)
-12.11 库(二)
-12.12 makefile文件(一)
-12.13 makefile文件(二)
-12.14 makefile文件(三)
-12.15 编程实践
-第十二讲 Linux系统编程基础--编程实践提交入口
-13.01 提纲
-13.02 进程基本概念
-13.03 信号
-13.04 进程管理(一)
-13.05 进程管理(二)
-13.06 进程管理(三)
-13.07 进程间通信(一)
-13.08 进程间通信(二)
-13.09 进程间通信(三)
-13.10 进程间通信(四)
-13.11 进程池
-13.12 编程实践
-第十三讲 进程编程--编程实践提交入口
-14.1 提纲
-14.2 线程基本概念
-14.3 线程管理(一)
-14.4 线程管理(二)
-14.5 线程管理(三)
-14.6 线程管理(四)
-14.7 线程同步机制(一)
-14.8 线程同步机制(二)
-14.9 C++11线程库(一)
-14.10 C++11线程库(二)
-14.11 C++11线程库(三)
-14.12 C++11线程库(四)
-14.13 C++11线程库(五)
-14.14 编程实践
-第十四讲 线程编程--编程实践提交入口
-15.1 提纲
-15.2 Internet网络协议
-15.3 套接字(一)
-15.4 套接字(二)
-15.5 编程实践
-第十五讲 网络编程--编程实践提交入口