我们首先来看第一节
程序抽象与面向对象
先从这样的一个例子开始
我们要设计一个抽象的数据类型
设计能够保存二维平面上点的
抽象数据结构
这个例子其实我们已经见过了
我们原来用结构化的程序设计的
思维模式写的这个代码
就是像这样一个组织结构
在我们的头文件里声明了一个结构体
struct POINT 我们只声明没有定义它
然后我们typedefstruct POINT * PPOINT
也就是说 在整个程序的接口中
我们实际提供的不是这个结构体
而是指向这个结构体的指针
我们同时提供了一系列的接口
从PtCreate、PtDestroy然后PtGetValue、PtSetValue
一直到PtPrint这些函数
来访问抽象的点的数据结构
我们说过 你按照这样的一个方式
来实现的代码 它实际上就是
符合数据封装与信息隐藏的要求的
这样的话 会保证我们这样一个库的
实现细节尽可能地和库的使用者
是完全脱离开的
库的使用者就不会具有了解和维护
我们这个库的细节的负担
这是非常重要的一个设计思路
但是这样设计的程序代码呢
它实际上是有一个小问题
问题在哪里呢 问题就在
你只能定义指向这个结构体的指针
你并不能够定义这个结构体类型的变量
因为我们这个结构体的类型是未知的
我们仅仅声明了它 我们并没有定义它
POINT的结构体
我们仅仅声明了 而没有定义
所以你是不可以使用POINT这个结构体
来定义变量的
你只能定义PPOINT类型的变量
也就是指向这个结构体的指针
也就是说 像这样一个库的接口使用
其实是受限的
接下来的几张片子就是我们这个库的实现
我们首先要在库的代码里面
实现这个结构体struct POINT
要定义好它 然后一一实现我们函数
PtCreate、PtDestroy、PtGetValue、PtSetValue、
PtCompare、PtPrint、PtTransformIntoString
还有一个 我们需要使用到的
一个辅助函数DuplicateString
所有的这个实现中 你注意看
操纵的都是指向那个结构体的指针
这是我们在写库的代码的时候
需要特别注意的地方
我们前面讲了 你这样的一个实现
你只能处理这样的一个指针
这是它的一个问题
第二个 虽然我们将这个结构体的声明
和这个结构体所能够具有的方法
也就是它的行为
实际上封装在一个抽象的点库里面
属性和行为从我们的实现角度来讲
似乎是统一的
但我们其实并没有办法
要求程序员对所有的库的结构
按照一个特定的方式这样组织和使用
你比如说 他有可能
把那个结构体的定义抽取出来
然后放到了头文件里
这样的话 他不就可以用了嘛
这是非常重要的一个地方
我们按照这样一个实现完成了
这样的一个抽象库的一个表达
我们将它的属性
也就是这个结构体所具有的数据的
那些成员信息和在这些信息上边
所能够进行的操作
把它统一地封装在我们的源文件里
而在我们的接口上面
只提供它的型的一个描述——一个简单的描述
而不是内部实现细节
不是类型的实现细节
只有类型的简单描述
还有 可以在这个型上所进行的一种操作
当然我们实际上使用的是
指向这个结构体的指针
我们希望达到的目标就是
属性和行为的辩证统一
每一个这样的库
都按照这样一个方法来实现
那我就会说在我们程序中
结构体和这个结构体中所具有的方法
我们这个抽象的数据结构和
我们这个数据结构上面可以进行的操作集
全部封装成了一个单一的库
我们希望表达就是属性和行为
这样一个辩证统一概念
可是在结构化的程序设计里边
这样的属性和行为统一
并不是特别得完美无缺
因为实际上 我们的操作集
和我们的抽象数据结构仍然是分裂的
虽然我们表达在了同一个头文件里
但它实际上仍然是分裂的
这种分裂会导致用户 也就是库的使用者
在理解这个整个程序代码的时候
就有可能导致问题
尤其当你把很多个这样的结构体
混杂在一起的时候
很多个这样的抽象数据型
封装在一个单一的库的时候
属性和行为上边
就有可能在理解这个库的代码的时候
会带来额外的负担
所以说 当我们想表达这个数据封装
和信息隐藏概念的时候
如果你没有这样的一个类的概念
你就没有办法清晰地定义
这是我们前面特别谈到的
那么最重要的一个地方
就是我们怎么样才能够
通过一种特殊的机制将这样一个
抽象的数据类型的数据封装和信息隐藏
很好地利用起来
同时又让它的属性和行为
在语言的实现的概念上完成辩证统一
实现这一点就是面向对象技术
对象首先要表达的一个概念就是量
它仍然是一个我们说的变量和常量
这样一个量的概念 这是一个
这样的量和它的行为
应该统一地组织在一起
不要像我们刚才那个抽象数据型一样
把它割裂开
虽说放在同一个接口里 同一个实现里
但是它们之间仍然是分隔开的
没有完全的统一
所以我们希望它们能够
有机地组织成一个整体
第二个 我们希望的是
能够增强对象行为的主动性
我们不是在一个对象上施加一个操作
比如讲 我们的PtDestroy
我是要销毁一个特定的点
那么我们就要传那个点的指针
给PtDestroy那个函数
这样的一个销毁动作从行为角度来讲
它实际上是被动的
因为我要传一个参数进去给PtDestroy函数
让PtDestroy那个函数负责销毁它
我们希望所表达的
是这个对象的行为的主动性
也就是说 我们希望是一个点对象
它自己去发出一个销毁的动作
然后释放它自己
这个就叫对象行为的主动性
这个思考方法和我们结构化的程序思考方法
是有很大的不同的：一个是被动性的思维
一个是主动性的思维
从程序设计这个角度来讲
一个是被动式的思维模式
一个是主动式的思维模式
这两者之间是有很大不同的
那么很自然地我们就想
如果有这样一个接口库
那么我们整个程序的架构
就算相当完整的了
比如说一个struct POINT结构体
这个结构体里面呢
封装了它的数据成员
它包括x和y两个数据成员
封装了它对应的函数
从Create、Destroy一直到Print
我把这个点库的所有的数据
和它的操作集封装在一起
全都放在它的结构体的内部
这样的话不就完成了数据和代码
它的属性和行为的有效地统一了吗
我们想要的就是这样一个机制
这样的一个机制就叫面向对象技术
我们写出来的这个东西就是一个类
当然了 就我们这个代码的实现来讲
它事实上不是真正的C++代码
不是说它不可以工作 它可以工作
但是它和我们编程平时的习惯
是有一点点差异的
或者说有一点点不吻合的地方
首先当你使用一个struct结构体的关键字
来定义对象的时候
这里面的所有的成员都是公开的
除非你限定它 否则它们全都是公开的
外界都能够看到 也就是说x和y
像这样的一个数据外界是可见的
你没有做到数据封装和信息隐藏
从这个实现角度来讲
所以说我们这样的一个实现是有问题的