《C++面向对象高效编程(第2版)》——2.4 保护实现

2.4 保护实现

C++面向对象高效编程(第2版)
传统的面向过程编程,缺乏对实现者的保护。如果实现在生存期内无法保证自身的完整性,这样的实现则毫无用处。假如有人篡改了汽车速度表的传感装置会怎样?速度表将无法正确显示汽车的速度。假如自动柜员机(ATM)允许客户可以直接操作他人的账户会怎样?假如允许消费者不通过电源插座,直接使用电力电缆会怎样?

以上这些情况都有一个共同点,即它们只可通过特定的方式(接口)使用,没有其他方法(电脑黑客除外!)可绕过接口直接通向实现。驾驶员不能篡改速度表,至少是很难1。ATM允许个人对自己的账户执行某些受限操作,但不允许客户接触他人的账户。同样,直接从家门前的电线杆上(或配电箱中)接电是非法的。

这些例子中,接口(速度表、ATM、电源插座)都由实现支持,而且该实现由对应的接口来保护(即接口提供一个清晰且定义明确的方法访问实现)。换言之,实现以特定方式工作,并跟踪自身的状态。另外,实现假设它的状态仅能通过接口更改,如果违反此前提条件(即不知何故,实现的状态被直接从外部更改,并未通过提供的接口更改),则无法保证实现进行正确地操作。从接口的角度看,实现应通过公共接口运行(或由公共接口访问),以确保实现的完整性。

回顾一下影碟播放机的例子,当我们按下PLAY时,LD播放机的实现将进行检查,以确保:

(a)已载入碟片;

(b)已关闭碟片托架(或托盘)。

如果满足了以上条件,LD播放机将激活激光束装置和马达驱动器等,并开始读碟。为了检测条件(a)和(b),LD播放机可能使用某些微动开关,而且假设任何人都无法直接操作这些开关,只有实现才能控制微动开关。[ 这与我们常见的洗衣机和烘干机的关门传感器类似。这些电器附带的说明书中会清楚地说明,只有关闭洗衣机的门,洗衣机才可运转。如果仔细查看会发现,在洗衣机门的下面或后面有一个小型传感器。洗衣机门关闭时,开关被压低,说明门已关闭。如果好奇心驱使你按下开关,可以确信洗衣机在门未关闭的情况下,将开始运转!此时你已经绕过洗衣机的接口直接操作,而这样的行为可能导致你受伤或洗衣机受损。] 如果违反了这个假设,将无法保证播放机按指定说明运行。如果我们手动操控这些开关,愚笨的播放机则相信碟片已载入,并且托架已关闭;然后我们按下PLAY按钮,播放机一定会启动激光束装置,这可能会对播放机和用户造成不可挽回的损失(万幸的是,播放机的构造不会让这样的情况发生)。

如果用户按已发布的接口(published interface)操作(即按照说明使用),则不会出现这种情况。

图2-3

数据抽象引出了相关的概念:数据封装(data encapsulation)。只要存在由实现支持的带接口的对象,就一定存在实现隐藏(implementation hiding)(也称为信息隐藏)。有些信息对实现而言相当重要,但是对使用接口的用户而言却毫无价值,这些信息将被隐藏在实现中。实现由接口封装,而且接口是访问该实现的唯一合法途径(见图2-3)。

这就相当于说:通过门是进入房间的唯一的途径。LD播放机把激光束装置、马达和电子元件封装在内。被封装的项很可能是另一个对象(或一组对象),而马达和激光束的确是其他类的对象。注意,被封装的数据对于对象的实现极其重要。进一步而言,实现必须维护被封装信息的完整(或正确的状态)。

时间: 2024-11-02 00:39:09

《C++面向对象高效编程(第2版)》——2.4 保护实现的相关文章

《C++面向对象高效编程(第2版)》——4.2 无用单元收集问题

4.2 无用单元收集问题 C++面向对象高效编程(第2版) 在我们讨论无用单元收集1(garbage collection)之前,先了解一下何为无用单元(garbage),何为悬挂引用(dangling reference). 4.2.1 无用单元 所谓无用单元(garbage),是一块存储区(或资源),该存储区虽然是程序(或进程)的一部分,但是在程序中却不可再对其引用.按照C++的规定,我们可以说,无用单元是程序中没有指针指向的某些资源.以下是一个示例: main() { char* p =

《C++面向对象高效编程(第2版)》——4.6 对象赋值的语义

4.6 对象赋值的语义 C++面向对象高效编程(第2版) 赋值与复制的操作非常类似.在C++中,绝大多数的复制操作都由语言隐式调用(当对象按值传递或按值返回时).当通过现有对象创建新对象时,也进行了复制操作(但不是很频繁).与复制相反的是,赋值是必须由程序员显式调用的操作.然而,在Eiffel和Smalltalk中,赋值和复制操作都由程序员显式调用.这也是基于值的语言与基于引用的语言之间的区别. 在C++中,对于对象和基本类型赋值都具有相同的含义.把基本类型变量赋值给另一个(兼容的)基本类型变量

《C++面向对象高效编程(第2版)》——2.21 确保抽象的可靠性——类不变式和断言

2.21 确保抽象的可靠性--类不变式和断言 C++面向对象高效编程(第2版) 任何抽象都必须与客户履行它的契约(contract).当客户使用类时,他希望类的对象像其发布描述的那样运行正常.另一方面,类的实现者必须千方百计地确保对象运行正常.但是,类只有在客户履行自己那部分契约后,才能正确行使它的职责.例如,类的成员函数可能要求传入的参数为非零指针(non-zero pointer).只有满足此前提条件,成员函数才能保证它的行为.因此,客户必须履行一些义务.换言之,如果客户履行了她那部分契约,

《C++面向对象高效编程(第2版)》——2.30 has-a关系的重要性

2.30 has-a关系的重要性 C++面向对象高效编程(第2版) "has-a"关系(也称为关联.聚集.包含.组合)是在OOD(面向对象设计)中频繁使用的重要关系.但是,许多设计者和程序员都没有很好地理解其相关性,从而导致复杂僵化的设计和不必要的继承. 在OOD阶段,软件的复用主要通过两种方式完成:继承和包含.它们各有优缺点.优秀的设计者了解它们的局限性.优点和代价,可以灵活自如地应用它们.继承将在第5章.第6章以及第二部分的第12章中详细讨论. 包含是一项强大的设计技术,它比继承更

《C++面向对象高效编程(第2版)》——2.27 关联

2.27 关联 C++面向对象高效编程(第2版) 关联表示对象与不同类之间的结构关系(structual relationship),大多数关联都是二元关系(binary relation).类之间的多重关联(multiple association)和类本身的自关联(self association)都是合法的(见图2-19). 关联可以有一个名称,表明阅读方向的箭头为可选.注意,方向箭头为可选,但关联名必须显示.关联在不同的方向可以有不同的名称,但是,大多数情况下,没必要注明(特别是在已标出

《C++面向对象高效编程(第2版)》——3.2 类要素的细节

3.2 类要素的细节 C++面向对象高效编程(第2版) 3.2.1 访问区域 客户可以访问在类的public区域中声明的任何成员.我们可以把该区域看做是通用公共(general public)的接口,它没有任何保护,是类限制最少的区域.一个设计良好的类绝不会将数据成员包含在public区域,该区域只能包含成员函数.如果在public区域包含数据成员,那么无需类的实现者,仅通过编译器即可访问这些数据成员.这违反了数据抽象和封装原则.这也是我们为什么总将数据成员放在private或protected

《C++面向对象高效编程(第2版)》——第2章 什么是数据抽象

第2章 什么是数据抽象 C++面向对象高效编程(第2版) 面向对象编程的一项基本任务是创建带有适当功能的类,并隐藏不必要的细节(即抽象数据).下面,我们将用一个现实生活中的例子来解释数据抽象的概念. 绝大多数人都见过影碟播放机(laser disc player)(或LD播放机).现在,提出一个简单的问题:设计一个影碟播放机,要求易于使用和修改,可后续添加更多有用的功能. 注意: 如果难以理解影碟播放机,可以用CD播放机代替LD播放机,其设计原理类似.实际上,影碟播放机的功能是CD播放机功能的超

《C++面向对象高效编程(第2版)》——1.5 什么可以作为类

1.5 什么可以作为类 C++面向对象高效编程(第2版) 用简单的例子详细讨论类和对象非常容易,但是难点在于如何为给定的问题找出合适的类.我们必须理解类代表什么,何时将问题中的某些部分转化为类,而非数据,反之亦然.根据我们的定义,类拥有一组对象的共同属性(或者特性).怎样的共同才是共同?何时说这是一个类,而不是另一个类的对象?这些都是我们在学习OOP时会遇到的,和真正关心的问题. 当我们决定创建一个类时,第一个问题就是"是否确实需要这个类的多个实例?",如果答案为"是&quo

《C++面向对象高效编程(第2版)》——4.3 C++中的无用单元收集

4.3 C++中的无用单元收集 C++面向对象高效编程(第2版) C++提供类的析构函数专门处理无用单元收集,但是,这并不意味着无用单元收集只发生在析构函数中.实际上,某些其他成员函数也必须考虑无用单元收集. 类的析构函数给予对象最后一次机会释放它所获得的所有资源.在退出某作用域之前,由语言自动为在该作用域中创建的自动(基于栈)对象调用析构函数.此时,对象即将被销毁(也就是说,被对象占用的内存即将被系统回收).一旦析构函数完成,对象将彻底地消失. 删除(使用delete操作符)指向某对象的指针时

《C++面向对象高效编程(第2版)》——2.10 抽象数据类型—栈的实现

2.10 抽象数据类型-栈的实现 C++面向对象高效编程(第2版) 下面的示例用于说明,在C中一个简单栈的实现. Stack.h文件--让所有的抽象数据类型用户都可以使用Stack. typedef Stack* Stackld; typedef int bool; struct Stack { int data; / 在栈上存储元素 */ unsigned count; / 栈上元素的数量 / int top; / 栈顶部的指针 */ / 略去其他细节 .../ };``` Stack.c文件