当前课程知识点:基于Linux的C++ >  第十讲 操作符重载 >  10.13 操作符重载总结 >  LinuxCPP1013

返回《基于Linux的C++》慕课在线视频课程列表

LinuxCPP1013在线视频

LinuxCPP1013

下一节:LinuxCPP1014

返回《基于Linux的C++》慕课在线视频列表

LinuxCPP1013课程教案、知识点、字幕

我们可以对操作符的重载

进行一些简单的总结

C或C++提供了很多很多个操作符

而且随着C++11的版本的出现

操作符在增加得越来越多

又增加了好多个操作符

哪些操作符可以重载 哪些不可以重载

我们是需要说明的

不可以重载的操作符 同学们要记得

“::”操作符不可以

“?:”对不可以

“.”不可以

“.*”不可以

sizeof不可以

“#”不可以

“##”不可以

typeid不可以

这些操作符是不可以被重载的

剩下的都可以重载

这是指C++11以前的

C++11后来又添了很多操作符

那些就不在我们考虑范围之内

这些不可以重载 其它的都可以重载

那么这些操作符在重载过程中

要遵循什么样的原则呢

正常情况下 我们列出来这些原则

同学们一定要记得遵守

这些原则其实不是特别复杂

只要记住就行了

一个 当你重载操作符的时候

你只能重载已有的操作符

你不能创建新的操作符

对于程序员来讲 没有这个权利

创建新操作符 这是第一个

第二个 你要记得

操作符本身 它实际上也是一个函数

所以重载本身必须遵循我们的

函数重载的原则

函数签名必须是不一样的

重载的操作符不能改变

操作符的优先级和结合性

这一点是不允许你改变的

也不能改变我们这个

操作符的操作数个数和它的语法结构

这都是不能变的

重载的操作符不能改变

它作用于内部类型对象上面的含义

所以它只能和我们

用户自定义的对象一块使用

而且你还要记得

你重载的这个用法实际上还应该

跟过去在功能上是一致的

形式上是统一的

也就是说你要保持重载的操作符的语义

和原始的语义没有变化

保持一致 否则别人很难用

不是说你一定是这样

你如果说 我真地把一个加法操作符

给它重载成一个减法操作

它行不行呢 行

你那么编程 它没问题 编译能通过

调用也能够正确执行

但是a+b的结果给你算出a-b的值来

你让使用你这个类库的那个程序员……

你想想他是什么心情

你就知道 你这么处理

它实际上是毫无道理的

你保持语义不变

这是一个非常重要的原则

应该这么去做的 操作符重载的时候

大部分操作符

都是既可以当成员函数来重载

也可以当友元函数来重载的

你只需要记住

如果是重载为类的成员函数的话

它就隐含着一个this指针

所以名义上它就会少一个参数

实际上它不少

这是非常重要的一个地方

它是少一个参数的

如果你把重载为类的友元函数

因为没有这个隐含的this指针

所以这两个双操作数你都要传

单参数的话 不重载为类的友元函数

我们待会来讨论

成员函数与友元函数的选择

有些基本的原则就是

一般来讲全局的常用的操作符

比如关系操作符、逻辑操作符

像这个流操作符

我们往往重载为类的友元函数

这是全局的操作符

涉及到对象特殊运算的这样操作符呢

哪怕是全局的

我们有时也把它重载为类的成员函数

一般单目操作符重载为成员函数

就不把这个函数的名字公开在外部

形成全局的嘛

你重载为友元函数的话

那个函数往往就是全局的

所以如果单目运算的话

就往往把它重载为一个成员函数

而不是友元函数 双目操作符呢

我们习惯于把它重载为类的友元函数

这是一个更好的方法

这样的话 左操作数和右操作数

可以相当灵活地去设置

使用其实更加方便

有些双目操作符是不能够

重载为类的友元函数的

要特别强调这一点

比如讲赋值操作符 这个不可以

“()”就是函数调用操作符 不可以

“[]”操作符 不可以

那个“->”操作符

那实际上是一个选员操作符

一个指针 引领它的目标结构体的一个成员

那是个引领操作符 选员 对吧

它是不可以的

你不能够把它重载成友元函数

必须隐式地提供它的this指针

这是非常重要的一个地方

类型转换操作符

只能重载为类的成员函数

你不能重载为它的友元函数的

重载的操作符

一般参数采用引用格式传递

主要是为了和我们的数学运算相协调

其实我们前面已经解释过这个问题了

我们现在作为一个总结

我们就把这个例子

给大家演示一下你就知道

如果我定义了两个Couple类的对象a和b

又有一个对象c

然后我把c=a+b这样一个动作

数学上来讲它是一个标准格式

我们就这么写的 把俩数相加 对吧

如果你的定义 重载的操作符定义

返回值是Couple

然后operate+是传递两个Couple类的指针

如果是这样的定义

那么当你调用这个函数的时候

你其实不能那么写

因为左操作数和右操作数

你都必须传指向Couple类的一个对象的指针

所以你应该写&a、&b 对吧

这两个对象在这儿 a和b

你传的是&a、&b 你好崩溃啊

数学上是这么写的吗

不是这么写的

那你可能就会说

我前面就写Couple *a、Couple *b

然后我new它们嘛

恰好这地方不就写c=a+b吗

是的 那样就可以了

但是那就限定了你所有的对象

必须是个指针 必须动态构造

那个好麻烦哪 对吧

那不方便 所以正常的时候

我们写的时候

引用传递的目的就在这里

就是为了处理这个问题的

以与数学运算相协调 就这个意思

所以我们的操作符重载

它的参数要使用引用格式

不管是左值引用还是右值引用

最后几张幻灯片

将给同学们简单地罗列一下

C++操作符重载的函数原型

这是我们推荐的函数原型

你平时操作符重载的时候

应该按照这样的一个模式进行操作

换作其它模式 有的时候不是不可以

但是它并不是特别恰当的方案

普通四则运算 加减乘除余这种模式

包括我们这个标量乘

我都把它列出来了 包括关系运算六个

基本的格式其实是一样的

然后你看到我们这里面有逻辑运算

可以被重载

它是按照像这样的一个格式的

逻辑运算与、逻辑运算或都是双目的

然后逻辑非 它当然是单目的

你看格式其实是不一样的

然后是单目的运算:正号运算、负号运算

取正取负的

还有四个递增递减造作符

前缀递增、后缀递增、

前缀递减、后缀递减

四个基本的格式 按照这个模式

位操作符 位运算

因为我们以前没解释过位运算

同学们知道有它就行了

平时我们不建议重载

还有动态存储管理的操作符

new或delete给我们做动态存储管理的

那么这两个操作符都可以被重载

重载的格式实际上有好几个版本

new不仅有数组版本一个

还有单版本的 实际上单版本有三个

一个是带一个参数

一个是带两个参数的

另外一个还带着两个参数的

尤其是第三种 new版本

它带着一个哑型指针

作为一个基地址的参数

它意味着它的内存分配

将在一个固定的内存区域

而这个内存区域是已经分配好的

然后我们新创建一个对象

就不再真正分配内存

而只是在已经分配好的

就是base指针所指向的

那段内存区域里

为我们新的对象

划定一个存储空间保存

这个我称它为定位创生

创生就是创造出来

把那个对象给它创造出来 就那个意思

在那个固定位置

而固定位置代表内存

以前已经分配好了

不管是动态分配还是静态分配

反正分配好了的 就这个模式

这个new操作符重载

有的时候相当有意义

为什么呢 就是我们的应用程序

我需要频繁地开辟一些小数组

很小 但是很频繁

因为程序语义本身要求这么做

那么频繁从全局里面

去new、delete、new、delete 很讨厌

要从全局堆里面进行分配

效率其实上是低的

在这种时候 我可以在程序运行一开始

就划定一个非常大的存储空间

上来从操作系统中

把这个存储空间给分配过来 要过来

然后我应用程序内部

每次需要分配小数据对象

想返回的时候

就在我这个分配空间里面

一个接着一个地去分配和管理它

固定在同样的小片区域里

这个内存区域里

这个内存区域我们称它为缓冲池

你就可以重载这个new操作符

来处理你应用程序的特定对象的

存储管理的问题

你可以在这个过程中

提升整个程序的效率

你甚至可以为你的应用程序

提供垃圾回收机制 处理这个指针问题

相当重要的一个设计细节

new和delete既可以重载为全局的

也可以重载为类的成员函数

对于大部分情况下

重载为类的成员函数要更安全一些

重载为全局函数

有的时候一旦覆盖了全局的new版本

可能会导致我们的程序

出现难以预料的结果

所以重载的时候需要特别小心

接下来就是赋值操作符

一堆呢 不仅仅是有基本赋值

包括移动语义和拷贝语义的

实际上还有加赋、减赋 对吧

除了加赋、减赋

还有位运算的赋值呢 一堆

下标操作符 还有函数调用操作符

就是我把小括号对(它不是代表着函数调用嘛?)

我也把那个操作符重载一遍

这样的话 这个函数上就有一个operator()

这样的一个函数

就让这个对象可以像函数一样

去运行一下 这是很典型的

参数当然个数可选 想要多少个都可以

没关系

函数调用操作符有时候会很神奇

它会给我们带来很重要的一个结果

就像我们刚才讲的流对象那样

它的操纵符带参数的

那它其实就是一个函子

就意味着它事实上在实现上

就是重载了函数调用操作符的

一个函数对象 它就是一个对象

上面有一个operate<被重载了

就可以像函数一样的运作 就这意思

我们下一讲会实现自己的函子

你可以看到我们怎么实现的

类型转换操作符

可以把这个类转换成另外一个类

那么你就可以提供

这个类型转换的操作符

可以 必须按照这个模式来

它只能重载为类的成员函数

还有逗号操作符 虽然很怪

但是逗号操作符本身是可以被重载的

注意这个 本身是可以被重载的

但是我不建议你这么干

因为它优先级真得很低

而且真得没有必要

接下来是我们的指针与选员操作符

有点讨厌 “&”操作符是取址的

“*”操作符是引领的 这两个简单

然后是这个“*”操作符 还是引领的

两个版本 引领操作符双版本

这三个简单 后面有一个“->”操作符

还是选员操作符

看上去也不那么复杂 对吧

返回的是那个指针

选员操作符也是两个版本

引领操作符俩版本 选员操作符俩版本

我们总共是5个版本

还有一个很怪异的“->*”操作符

它一样是一个选员操作符

但它比较特殊 它是什么呢

它是指向类成员的一个指针

在我们前一讲讲类与对象的时候

我们根本就没有讨论这个问题

因为这个技术细节太偏了

当我们不需要使用它的时候

我真地不能去介绍它

介绍它 同学们会觉得太奇怪

不知道它干嘛用的 我们后面有例子

一旦你见到了使用它的例子

你就会知道我们为什么需要它

那个时候再去处理这个问题

你对它认识就会很深刻 就会明白

最后就是我们的流操作符

两个输入输出流

我们的插入符、提取符

按照这个模式重载它们就可以了

基于Linux的C++课程列表:

第一讲 C/C++基本语法元素

-1.1 提纲

--LinuxCPP0101

-1.2 程序设计的基本概念

--LinuxCPP0102

-1.3 简单C/C++程序介绍

--LinuxCPP0103

-1.4 程序设计的基本流程

--LinuxCPP0104

-1.5 基本语法元素

--LinuxCPP0105

-1.6 程序设计风格

--LinuxCPP0106

-1.7 编程实践

--LinuxCPP0107

-第一讲 C/C++基本语法元素--编程实践提交入口

第二讲 程序控制结构

-2.1 提纲

--LinuxCPP0201

-2.2 结构化程序设计基础

--LinuxCPP0202

-2.3 布尔数据

--LinuxCPP0203

-2.4 分支结构

--LinuxCPP0204

-2.5 break语句

--LinuxCPP0205

-2.6 循环结构

--LinuxCPP0206

-2.7 编程实践

--LinuxCPP0207

-第二讲 程序控制结构--编程实践提交入口

第三讲 函数

-3.1 提纲

--LinuxCPP0301

-3.2 函数声明、调用与定义

--LinuxCPP0302

-3.3 函数调用栈框架

--LinuxCPP0303

-3.4 编程实践

--LinuxCPP0304

-第三讲 函数--编程实践提交入口

第四讲 算法

-4.1 提纲

--LinuxCPP0401

-4.2 算法概念与特征

--LinuxCPP0402

-4.3 算法描述

--LinuxCPP0403

-4.4 算法设计与实现

--LinuxCPP0404

-4.5 递归算法(一)

--LinuxCPP0405

-4.6 递归算法(二)

--LinuxCPP0406

-4.7 容错与计算复杂度

--LinuxCPP0407

-4.8 编程实践

--LinuxCPP0408

-第四讲 算法--编程实践提交入口

第五讲 程序组织与开发方法

-5.1 提纲

--LinuxCPP0501

-5.2 库与接口

--LinuxCPP0502

-5.3 随机数库(一)

--LinuxCPP0503

-5.4 随机数库(二)

--LinuxCPP0504

-5.5 作用域与生存期

--LinuxCPP0505

-5.6 典型软件开发流程(一)

--LinuxCPP0506

-5.7 典型软件开发流程(二)

--LinuxCPP0507

-5.8 编程实践

--LinuxCPP0508

-第五讲 程序组织与开发方法--编程实践提交入口

第六讲 复合数据类型

-6.1 提纲

--LinuxCPP0601

-6.2 字符

--LinuxCPP0602

-6.3 数组(一)

--LinuxCPP0603

-6.4 数组(二)

--LinuxCPP0604

-6.5 结构体

--LinuxCPP0605

-6.6 编程实践

--LinuxCPP0606

-第六讲 复合数据类型--编程实践提交入口

第七讲 指针与引用

-7.1 提纲

--LinuxCPP0701

-7.2 指针基本概念

--LinuxCPP0702

-7.3 指针与函数

--LinuxCPP0703

-7.4 指针与复合数据类型(一)

--LinuxCPP0704

-7.5 指针与复合数据类型(二)

--LinuxCPP0705

-7.6 字符串

--LinuxCPP0706

-7.7 动态存储管理(一)

--LinuxCPP0707

-7.8 动态存储管理(二)

--LinuxCPP0708

-7.9 引用

--LinuxCPP0709

-7.10 编程实践

--LinuxCPP0710

-第七讲 指针与引用--编程实践提交入口

第八讲 链表与程序抽象

-8.1 提纲

--LinuxCPP0801

-8.2 数据抽象(一)

--LinuxCPP0802

-8.3 数据抽象(二)

--LinuxCPP0803

-8.4 链表(一)

--LinuxCPP0804

-8.5 链表(二)

--LinuxCPP0805

-8.6 链表(三)

--LinuxCPP0806

-8.7 链表(四)

--LinuxCPP0807

-8.8 函数指针(一)

--LinuxCPP0808

-8.9 函数指针(二)

--LinuxCPP0809

-8.10 抽象链表(一)

--LinuxCPP0810

-8.11 抽象链表(二)

--LinuxCPP0811

-8.12 编程实践

--LinuxCPP0812

-第八讲 链表与程序抽象--编程实践提交入口

第九讲 类与对象

-9.1 提纲

--LinuxCPP0901

-9.2 程序抽象与面向对象

--LinuxCPP0902

-9.3 类类型

--LinuxCPP0903

-9.4 对象(一)

--LinuxCPP0904

-9.5 对象(二)

--LinuxCPP0905

-9.6 类与对象的成员(一)

--LinuxCPP0906

-9.7 类与对象的成员(二)

--LinuxCPP0907

-9.8 类与对象的成员(三)

--LinuxCPP0908

-9.9 继承(一)

--LinuxCPP0909

-9.10 继承(二)

--LinuxCPP0910

-9.11 继承(三)

--LinuxCPP0911

-9.12 多态(一)

--LinuxCPP0912

-9.13 多态(二)

--LinuxCPP0913

-9.14 编程实践

--LinuxCPP0914

-第九讲 类与对象--编程实践提交入口

第十讲 操作符重载

-10.1 提纲

--LinuxCPP1001

-10.2 四则运算符重载(一)

--LinuxCPP1002

-10.3 四则运算符重载(二)

--LinuxCPP1003

-10.4 关系与下标操作符重载

--LinuxCPP1004

-10.5 赋值操作符重载(一)

--LinuxCPP1005

-10.6 赋值操作符重载(二)

--LinuxCPP1006

-10.7 赋值操作符重载(三)

--LinuxCPP1007

-10.8 赋值操作符重载(四)

--LinuxCPP1008

-10.9 赋值操作符重载(五)

--LinuxCPP1009

-10.10 流操作符重载(一)

--LinuxCPP1010

-10.11 流操作符重载(二)

--LinuxCPP1011

-10.12 流操作符重载(三)

--LinuxCPP1012

-10.13 操作符重载总结

--LinuxCPP1013

-10.14 编程实践

--LinuxCPP1014

-第十讲 操作符重载--编程实践提交入口

第十一讲 泛型编程

-11.1 提纲

--LinuxCPP1101

-11.2 泛型编程概览

--LinuxCPP1102

-11.3 异常处理机制(一)

--LinuxCPP1103

-11.4 异常处理机制(二)

--LinuxCPP1104

-11.5 运行期型式信息(一)

--LinuxCPP1105

-11.6 运行期型式信息(二)

--LinuxCPP1106

-11.7 模板与型式参数化

--LinuxCPP1107

-11.8 题外话:术语翻译

--LinuxCPP1108

-11.9 泛型编程实践(一)

--LinuxCPP1109

-11.10 泛型编程实践(二)

--LinuxCPP1110

-11.11 泛型编程实践(三)

--LinuxCPP1111

-11.12 泛型编程实践(四)

--LinuxCPP1112

-11.13 泛型编程实践(五)

--LinuxCPP1113

-11.14 泛型编程实践(六)

--LinuxCPP1114

-11.15 泛型编程实践(七)

--LinuxCPP1115

-11.16 泛型编程实践(八)

--LinuxCPP1116

-11.17 泛型编程实践(九)

--LinuxCPP1117

-11.18 泛型编程实践(十)

--LinuxCPP1118

-11.19 编程实践

--LinuxCPP1119

-第十一讲 泛型编程--编程实践提交入口

第十二讲 Linux系统编程基础

-12.1 提纲

--LinuxCPP1201

-12.2 程序执行环境(一)

--LinuxCPP1202

-12.3 程序执行环境(二)

--LinuxCPP1203

-12.4 程序执行环境(三)

--LinuxCPP1204

-12.5 程序执行环境(四)

--LinuxCPP1205

-12.6 输入输出(一)

--LinuxCPP1206

-12.7 输入输出(二)

--LinuxCPP1207

-12.8 文件系统

--LinuxCPP1208

-12.9 设备

--LinuxCPP1209

-12.10 库(一)

--LinuxCPP1210

-12.11 库(二)

--LinuxCPP1211

-12.12 makefile文件(一)

--LinuxCPP1212

-12.13 makefile文件(二)

--LinuxCPP1213

-12.14 makefile文件(三)

--LinuxCPP1214

-12.15 编程实践

--LinuxCPP1215

-第十二讲 Linux系统编程基础--编程实践提交入口

第十三讲 进程编程

-13.01 提纲

--LinuxCPP1301

-13.02 进程基本概念

--LinuxCPP1302

-13.03 信号

--LinuxCPP1303

-13.04 进程管理(一)

--LinuxCPP1304

-13.05 进程管理(二)

--LinuxCPP1305

-13.06 进程管理(三)

--LinuxCPP1306

-13.07 进程间通信(一)

--LinuxCPP1307

-13.08 进程间通信(二)

--LinuxCPP1308

-13.09 进程间通信(三)

--LinuxCPP1309

-13.10 进程间通信(四)

--LinuxCPP1310

-13.11 进程池

--LinuxCPP1311

-13.12 编程实践

--LinuxCPP1312

-第十三讲 进程编程--编程实践提交入口

第十四讲 线程编程

-14.1 提纲

--LinuxCPP1401

-14.2 线程基本概念

--LinuxCPP1402

-14.3 线程管理(一)

--LinuxCPP1403

-14.4 线程管理(二)

--LinuxCPP1404

-14.5 线程管理(三)

--LinuxCPP1405

-14.6 线程管理(四)

--LinuxCPP1406

-14.7 线程同步机制(一)

--LinuxCPP1407

-14.8 线程同步机制(二)

--LinuxCPP1408

-14.9 C++11线程库(一)

--LinuxCPP1409

-14.10 C++11线程库(二)

--LinuxCPP1410

-14.11 C++11线程库(三)

--LinuxCPP1411

-14.12 C++11线程库(四)

--LinuxCPP1412

-14.13 C++11线程库(五)

--LinuxCPP1413

-14.14 编程实践

--LinuxCPP1414

-第十四讲 线程编程--编程实践提交入口

第十五讲 网络编程

-15.1 提纲

--LinuxCPP1501

-15.2 Internet网络协议

--LinuxCPP1502

-15.3 套接字(一)

--LinuxCPP1503

-15.4 套接字(二)

--LinuxCPP1504

-15.5 编程实践

--LinuxCPP1505

-第十五讲 网络编程--编程实践提交入口

课程文档

-课程PDF文件

LinuxCPP1013笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。