max()与min()函数的实现没有对数组元素的存储做特殊的假设,因此我们需要检查数
组的每个元素,如果我们要求所有的元素已经排序,则这两个操作就变得非常简单,只要索
引第一个元素和最后一个元素即可,而且如果已知元素已经排序,那么查找一个元素的存
在就会更加高效,但是对数组进行排序增加了Array 类实现的复杂性,我们的设计出错了吗?
实际上,我们现在是否犯了错误与我们做出的选择息息相关,排序的数组是一种特殊的
实现,需要时它完全必要。否则,支持排序数组的额外开销就是一项负担,我们的实现是
比较通用的,在大多数情况下是足够的,它支持更广阔范围内的用户,不幸的是如果用户
绝对需要排序数组的行为,那么我们的实现就不能提供支持,对用户来说他没有办法对
min() max()以及find()这些函数比较通用的实现进行改写。实际上,我们选择的通用实现并不适合特殊的环境。
另一方面,我们的实现对另外一类用户而言又针对性太强了,对索引的范围检查为每次
访问元素增加了额外的负担。在设计中,我们没有考虑这样的开销,而是假设如果结果不正确,那么速度再快也没有价值,但是这种设计至少对于某一类主要
用户实时虚拟和虚拟现实提供商就不成立。在这种情况下数组代表复杂3D 几何图形
的顶点,场景飞快地变化以至于一些偶然的错误不会被看到,但如果访问速度太慢了那
么实时效果就会被打破,我们实现的数组类虽然比没有范围检查的数组类会更安全,但是在这样的实时应用领域却不够实际,
我们怎样才能支持这三种用户的需要呢?解决的方案已经多多少少体现在代码中了,例
如范围检查局限在下标操作符中,去掉check.range()的调用重新命名该数组。现在我们
就有了两种实现,一个有范围检查,一个没有范围检查。进一步拷贝一份代码并把它修改
成针对已排序的数组,现在我们就有了对已排序数组的支持。
// 未排序也没有边界检查
class IntArray{ ... };
// 未排序但支持边界检查
class IntArrayRC{ ... };
// 已排序但没有边界检查
class IntSortedArray{ ... };
这种方案的缺点是什么呢
1.我们必须维护三个包含大量重复代码的数组实现,我们更希望把这些公共代码只保留
一份,然后,由这三个数组类以及其他一些我们以后会选择支持的数组类共享。比
如可能会是一个带有边界检查的排序数组
2.由于三个数组实现是完全独立的类型,所以我们必须编写独立的函数来操作它们,尽
管函数内的一般性操作都是相同的。例如
void process_array( IntArray& );
void process_array( IntArrayRC& );
void process_array( IntSortedArray& );
我们希望只编写一个函数,它不但能接受现有的数组类,而且还能够接受任意将来的
数组类。只要同样的操作集合也能够应用到这些类上,
面向对象的程序设计方法正是为我们提供了这样一种能力。上面第1 项可由继承
inheritance 机制提供。当一个IntArrayRC 类也就是一个带有范围检查的IntArray 类
继承了IntArray 类时,它就可以访问IntArray 的数据成员和成员函数。而不要求我们维护两
份代码拷贝。新的类只需提供实现其额外语义所必需的数据成员和成员函数。
在C++中,被继承的类如本例中的IntArray 被称作基类base class,新类被称作
从基类派生derived 而来,我们把它叫做基类的派生类derived class 或子类型subtype。