当前课程知识点:基于Linux的C++ >  第十讲 操作符重载 >  10.5 赋值操作符重载(一) >  LinuxCPP1005

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

LinuxCPP1005在线视频

LinuxCPP1005

下一节:LinuxCPP1006

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

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

接下来的一节

我们讨论赋值操作符的重载

赋值操作符重载比较复杂

涉及到几个地方

一个是赋值操作符重载的

一般形式是什么样的

第二个就是复合赋值操作符的重载

比如加赋、减赋、乘赋、除赋、余赋

这几种赋值操作符的重载

我们应该怎么去处理

然后是非常重要的一节

就是赋值构造和拷贝构造

我们上一讲讨论类与对象的时候

已经谈到过如何进行拷贝构造

但我们这里的一讲 将特别讨论

赋值构造和拷贝构造的具体实现

包括在构造一个对象的时候

我们是使用深拷贝机制

还是使用浅拷贝机制

最后一节 我们讨论C++11版本里面

提供的新的移动语义

在C++11之前

这个移动语义是不存在的

只有在C++11之后

才引入了新的移动语义

它主要是为了解决

深拷贝和浅拷贝的一些问题

我们首先来看

赋值操作符重载的一般形式

一般来讲 赋值操作符的重载

和以前的几种操作符的重载都不太一样

它最重要一个地方

就是将要返回

对本对象的一个引用

赋值嘛 就是要把另外一个数据

传给我们这个当前的对象

注意 当我们把这个赋值操作符

重载为类的成员函数的时候

它的this指针将指向我们这个本对象

而本对象将接受别的对象的值

这是赋值操作的一个最基本的语义

所以我们重载这个赋值操作符的时候

我们应该返回当前对象的一个引用

这样能够保证连续赋值的机制能够工作

这是非常重要的一个设计细则

参数嘛 当然传的是

对另外一个数偶对象的引用

我们看函数的实现

operator= 赋值的时候

只需要实现_a字段给_a字段

_b字段给_b字段 就OK了

想法其实是非常直接的

有一个特别的地方就是:if(*this==c)

this所指向的本对象

和c传过来的那个对象

如果两者在数值上是完全相等的

或者你认为它们是相等的

那么这样一个对象的赋值就没有意义

因为这两个量是一样的嘛

你还赋值它干嘛呢

赋值也不改变它的语义

也不改变它的结果

所以这个时候就可以不赋值

不赋值的结果

我们就直接return *this

赋值完了以后 我们要return*this

我们要引领this所指向的目标数据对象

这个就是我们的赋值操作符

我们必须按照这样一个模式进行操作

赋值 它其实就是一个拷贝

它把另外一个对象拷贝给我们这个本对象

这是非常重要的一个地方

回过头来看我们赋值操作符重载的语义

Couple& operator=

参数传constCouple& c

一定要按照这个方式来写

不按照这个方式来写

就和C++预定义赋值操作的语义

是不吻合的 记住这一点

再看实现 if( *this==c),return *this

赋值 return *this

一定要按照这个模式进行实现

有一个细节需要额外地说明一下

就是这个if( * this==c)的判定

要不要做的问题

如果你做了这个判定

并且当它满足条件的时候直接return*this

两个数偶类的对象是一样的

所以不需要赋值

那么它就不会产生额外的拷贝

但是你要注意

我们这里面多了一个if判定

所以实际上多了一个if语句

当这个对象的拷贝动作

在我们程序中需要频繁进行的时候

而且大部分时候

它们都不相等

这两个对象都不相等

所以做这个额外的判定

事实上没有增加我们的程序效率

反而降低了我们的程序效率

所以在某些场合

不判定这两个对象是不是相等

就直接拷贝 其实更合适

编程的时候要特别去注意这一点

接下来就是我们的复合赋值操作符

就是那个赋值操作符简写形式

我们加赋、减赋、乘赋、除赋、余赋

其实不仅仅这么多 还有呢

我们先看几个简单的例子

就用其中的加赋、乘赋

我们直接就用这个例子

只是一个示例

减赋、余赋、除赋

跟这个性质其实都一样的

当然我们在乘赋这个动作上边

我们同样重载了那个标量乘法的那个版本

我们也要把它写进去

Couple& operator+=(constCouple& c )

Couple& operator*=(constCouple& c)

Couple& operator*=(constint& k)

三个复合赋值操作符的重载

格式跟刚才非常得类似

返回值是一样的 参数一样的

除了这个标量乘法是个constint&

实现上也是类似的 operator+=

就把c类型的_a字段、_b字段

分别累加到_a、_b这两个字段上就OK了

然后return* this 做完了

加赋就这个事 乘赋 乘上去 OK了

标量乘 直接乘k

两字段都乘k 返回 * this 完事了

这个就是复合操作符的重载

实现上一样很简单

有一个很特殊的操作符

就是递增递减操作符

它实际上也是复合赋值操作符的一大类

只不过我们把它单独列出来

因为“++”、“--”都涉及到

对当前那个对象做一个加法或减法 对吧

它实际上也涉及到对本对象值的修改

所以它仍然算是一种广义的赋值

如果我们为这个数偶类

重载我们的递增递减操作符的时候

就要特别注意

因为那个“++”、“--”操作符

可以是前缀的 也可以是后缀的

不管是前缀的还是后缀的

它们都只有一个单操作数

也就是说它们是单目操作符

那么我们重载它的前缀递增和前缀递减

后缀递增和后缀递减的时候

我们怎么区分它的前缀和后缀的关系

所以为了区分重载的操作符

它到底是前缀操作符还是后缀操作符

你必须按照这个格式来写

Couple& operator++()

Couple operator++(int)

第一种方案表示我们重载的

是前缀操作符

第二种方案带一个单参数版本的

那表示我们重载的是后缀操作符版本

int后面跟着那个参数我们从来不用

它是那个操作符第二个操作数

有吗 没有

哪怕是后缀递增 它也没有 我们不用

写它唯一的目的是为区分

它和前缀操作符

前缀是无参数的 后缀是有参数的

这是前缀操作符和后缀操作符

重载时候的第一点差别

我们用一个参数来确定它是

前缀的还是后缀的

有参数就是后缀的

没参数就是前缀的 这是一个

第二个 返回值不一样

前缀操作符返回值是本对象的一个引用

所以写的是Couple&

后缀操作符返回的是本对象的一个拷贝

所以返回值是Couple

返回值类型是不一样的

同学们要特别注意这一条

这是C++要求的语义

“++”操作符、“--”操作符、前缀、后缀的原始实现

就是按照这个语义来实现的

所以当你重载的时候

一定要维持着“++”、“--”操作符的

原始的语义不变

这是我们重载这个操作符的格式

一定要记住

实现上就需要特别注意

前缀递增和后缀递增之间的差别

如果它是一个前缀的

那么我们在实现它的时候

++_a,++_b,return* this 就完事了

这就是一个前缀的

我就返回对本对象的一个引用

没有问题 就按照这个方式来写

可是如果是一个后缀的递增

那么就需要特别注意

就是我们首先要通过*this这个对象

来构造一个临时的Couple对象_t

一个局部量

我就用*this指针去拷贝构造它

拷贝构造之后

我们_a++,_b++

然后不能return*this

我们只能return _t

拷贝后的那个对象

这是后缀递增的语义

它是产生了一次替换

返回的不再是原始的那个对象

而是原始对象的一个拷贝

这才能够保证“++”操作符的运算

将在我们的这个表达式中

其它的表达式、操作符都算完了

它才最后算

先参与运算 后递增递减

不就是这个意思嘛

赋值操作符的返回值

有一点需要特别注意

除了后缀递增递减操作符之外

返回对本对象的一个引用

应该返回的是这个

最主要的目的就是和C++本身的语义

要完全吻合 这是一个

你如果真的返回一个对象

你就说我和语义吻合 行不行呢

其实也不是说不可以

但是你要特别小心

就是你真地返回这样的一个对象

它事实上是需要一个额外的拷贝构造的

你要构造一个对象 然后才能返回它

这个构造 当这个对象尺寸很大的时候

它实际上是对整个程序的效率

是有很大影响的

所以要特别注意这一点

如果你不需要使用返回值

来进行连续的赋值动作的话

你比如讲我把c=b=a

这个意思就是什么呢

就是要把a给b 然后把b再给c

把b赋值为a的那个结果然后再给c

它是个连续的赋值动作

如果你不想干这个事

那么这个返回值类型

实际上可以设成void 可以不写

还是刚才那句话

它就和C++的标准语义是不吻合的

我们不推荐你这么写

但并不意味着你不能这么写

基于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文件

LinuxCPP1005笔记与讨论

也许你还感兴趣的课程:

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