当前课程知识点:基于Linux的C++ >  第九讲 类与对象 >  9.6 类与对象的成员(一) >  LinuxCPP0906

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

LinuxCPP0906在线视频

LinuxCPP0906

下一节:LinuxCPP0907

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

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

接下来一节是类与对象的成员

这一节的内容比较多 总共包括7个主题

一个是内联函数 一个是常数据成员

第三个是常成员函数

第四个和第五个

是静态数据成员和静态成员函数

第六个是静态常数据成员

最后一个是友元函数与友元类

我们首先来看内联函数

内联函数的最主要的目的是用于程序优化

展开函数的代码

而不是进行直接的函数调用

就是说 如果我有一个函数

它代码量其实很短

如果你每次都调用这个函数

因为函数调用是需要开销的

所以实际上在程序运行的时候会很不经济

从执行时间 也就是效率这个角度来讲

它实际上是调用函数

还不如直接编写函数体内部的代码

直接执行它 内联函数就做这个事情

它就将这段代码直接展开到

那个函数调用的地方 不进行函数调用

从而提高了我们的程序效率

但使用内联函数的时候

有几点必须要特别注意

第一个 定义这个内联函数

必须在函数的定义前添加inline

这样的一个关键字

因为inline本身

只和这个函数的定义有关

和它的原型其实没关系

所以inline这个函数

是写在这个函数的定义的前面的

这是需要特别注意的一个地方

第二个 编译器必须能看见

内联函数的代码 才能替你把内联函数

展开到那个函数调用的位置

这也就意味着 在大多数情况下边

你的内联函数是必须写在头文件里的

你的一个工程项目包括很多个文件

如果其它的源文件要使用这个内联函数

你要保证这个代码能够展开到

另外一个文件里面去

那么这个内联函数的实现

你必须写在头文件里

只有这样 它包含头文件

它才能够展开这段代码

如果你写到这个源文件里

它是不知道这段代码的

所以它展开不了 所以正常情况下

内联函数必须写在头文件里 这是第二个

第三个 要在类定义中给出函数体的时候

你比如说你在类的定义的里边

实现一个函数

你不需要写它的函数原型——后面不是分号

而是直接跟着花括号体

把它的函数实现代码都写在类里边了

你前面不用写inline 它也是inline

这是一个主要的原则

接下来一个 函数体类

如果代码量很大 而且它包括着循环

那么不要使用内联 特别注意这一点

因为你函数代码体量很大

你使用内联的效果

它会导致我们整个程序的

代码空间急剧膨胀

你程序效率可能是经济的

但是整个程序的空间是不经济的

所以并不是一个好的选择

第五个 构造函数和析构函数有可能

隐含着一些附加的操作

因此大部分情况下边不建议写内联函数

使用内联的时候要慎重

最后一个 对于编译器来说

内联函数仅仅是一个建议

你在一个函数实现前面写上inline

那就表示你建议

编译器将这个函数实现为内联函数

编译器听不听你的

它自己有自主决定权

如果一个函数代码量很大

它认为把它作为内联函数不合适

你前面写了inline 它也不会inline

这个地方是需要特别注意的一个地方

我们看这样一个例子

GetOrigin、SetOrigin这两个成员函数

代码量都很短

就两条简单的赋值语句

那么如果我们在实现的时候

每次GetOrigin、SetOrigin都是进行函数调用

实际上函数调用开销

是远远大于函数本身的

所以把这样的函数

定义为内联是非常合适的

你写了一个inline

那么每次需要GetOrigin、SetOrigin的时候

都自动地将这一段代码

展开在这个函数的调用处

而不调用这个函数了

代码量膨胀也不算厉害

因为函数体本身很短

同时整个程序的执行效率得到了提高

所以内联函数的用处、好处就体现在这个地方

不过它仅仅是和程序优化这个目的有关

和整个程序的功能

和整个程序的实现本身

它实际上是没关系的

所以如果真得没有内联函数

对我们程序来讲其实是没关系的

就是程序运行的效率可能会低一些

其它没有任何影响

第二个就是常数据成员

一个类定义的里边

实际上不仅仅可以带有变量

也可以带有常量

比如说这样一个例子 classA

在一个类的定义里边

定义了一个成员叫num

它是一个常整数 constint

用这个类来构造一个特定对象的时候

这个对象里面的num

在程序运行期间是不变的

这是非常重要的一个地方

常数据成员

这也就意味着这样一个量

不可以对它进行赋值

那么对它设定值的唯一一个机会

就在初始化的那一瞬间

所以一个类的所有的常数据成员

必须进行初始化

初始化写在什么地方呢

其实就是在它的初始化列表里边

还有一种情况

我在一个类里边定义了一个函数

它需要读取这个类中的数据

同时我们明确地知道这个成员函数

是不会修改成员的数据的

那么这样的函数在实现的语义来讲

我们有必要把它实现成一个常函数

这样的一个定义格式就意味着

这个函数必须加上一个const修饰

因为const是左结合的

所以你不能写在函数原型的前面

你只能写在函数原型的后边

在函数的原型写完了 写const

后面跟着一个分号 这样才可以

实现这个函数的时候

也要在函数的头部写上const

表示这个函数的实现是常成员函数

如果你在函数的实现的时候

没写const 或者你在函数原型的时候

没写const 两者不匹配

对于编译器来讲

它将认为这是两个不同的函数

它们的函数签名是不一样的

所以你要写就都写 要不写就都不写

这是一定要注意的一个地方

一旦一个函数不需要修改成员变量的值

或者不能修改成员变量的值

那么就应该把它定义成常函数

常的成员函数不能够调用

类的非常成员函数

这是个非常明确的要求

因为非常成员函数

它就有可能修改成员属性的值

所以你调用它

就有可能打破常成员函数的语义

编译器本身不允许你做这样的调用

静态的成员函数不能定义为常成员函数

静态函数我们还没讲 我们待会再讨论

如果这个对象是一个常量

那么因为它的值不能修改

那就意味着你只能在它的上面

调用常成员函数

它的非常成员函数你都没有权利访问的

这是不允许操作的

正是在这个角度上来讲

如果你定义了一个类的类型

并且你知道未来你会用这个类类型

定义一个常对象

那么这个类类型的接口里边

那些凡是不需要修改成员的属性值的

这样的函数 都应该定义成常函数

接下来就是静态数据成员

静态数据本身我们其实已经见过了

它的意思就是我们的静态数据只有一份

那么在类类型的定义里面

如果我有一个数据成员

也就是它的一个属性 只包括一个

就是整个这个类——不管你通过这个类

定义了多少个对象

这些对象都共享同一个数据成员

这个数据成员就唯一一份

这个类的所有对象都共享它

那么在这种情况下边

你就应该将这个成员

定义为静态数据成员 普通的数据成员

每一个对象有自己的独立的一份

你用这个类类型定义一个对象

它就构造了一份它的全部数据成员

再定义了一个对象 又构造一份

这个两者是不一样的 它是两个物体

两个对象 两个数据

如果你要求一个特定的数据成员

在这个类中所有的对象上面都一样 就一份

那么你就应该使用静态数据成员

因为是所有的类都共享同一个对象

所以静态的数据成员

不会在这个类的对象上面分配存储空间

它是单独分配的

但是访问规则仍然是属于这个类的

你要通过类名去解析

这个静态的数据成员才可以

静态数据成员必须在

我们这个类的外部进行初始化

初始化这个动作

和它的访问规则本身是无关的

意思就是说

你不管是将这个静态的成员声明为public

还是private 还是protected

都应该在这个类的外部

单独地对它进行初始化

而不能在类的内部对它进行初始化

这是特别需要注意的一个地方

这个静态数据成员初始化的动作

应该放在源文件 而不是头文件里

因为它相当于一个变量的定义一样

除了静态数据成员 还有静态的成员函数

我们定义静态成员函数的目的

仍然是在一个类

而不是在一个对象上面对它进行调用

它就是为了访问类的静态的成员而设置的

定义一个静态数据成员

你要想访问这个类的静态数据成员

那么使用静态的成员函数

是一个非常恰当的方式

如果你要访问这个类的非静态的数据成员

那么你必须提供这个非静态的数据成员

到底是属于哪一个对象的

也就是说 你必须提供一个对象

或者一个对象的指针

或者一个对象的引用

这样的话 它才知道你提供的这个东西

到底是哪一个对象的

这是非常重要的一个地方

我们看这样的一个例子

class A,public

我定义一个静态成员函数staticintf()

定义一个静态函数staticintg

里面有一个静态的数据对象staticintcount

静态数据成员在外部对它进行初始化

这是“.cpp”代码 那是“.h”代码

然后静态的成员函数

我就按照像这样的一个方式

去访问它就行了

因为那个数据是类里独一份

所以我们这样的一个函数

理论上来讲 直接用它的名字

就访问到了那独一份的数据成员

如果你在这个静态成员函数里边

想访问它的非静态数据

你可以做 但是你必须告诉它

你到底访问的是哪一个对象

我们这里面传了一个constA的一个引用

A::g 访问的就是a引用的那个对象

所以returna.num

这是一个非常明确的要求

为什么呢 就是我们的静态的成员函数

它并没有缺省的this指针

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

LinuxCPP0906笔记与讨论

也许你还感兴趣的课程:

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