北航程序设计语言原理教材第10章
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第10章面向对象程序设计语言
当今席卷软件界的面向对象技术,近因是xerox公司1980年推出的Smalltalk-80语言。
当时,美国国防部正在推行投资五亿历时8年的Ada,试图先在军中统一再推广到全行业,使之成为软件开发的主导语言。
Ada是过程语言的新阶段,提供数据封装、数据抽象机制、并发、异常处理; 良好的易读性使Ada源代码能自成文档; 分别编译支持软件叠加和重用; 强类型增加软件的可靠性; Ada率先提出Ada程序设计支持环境APSE,把与机器相关的机制作为预定义环境(包括基本类型和输入/出机制),从而支持可移植性,能较好的满足软件工程可靠、易维护、可移植、可重用的目标。
但是,由于Ada太大(编译及环境当时的微机放不下),统得过死(廉价编译和环境推出太晚,一定要通过ACVC测试才能得到AJPO承认),且其本身反映了70年代末80年代初软件工程思想:严格管理和评审,导致软件开发周期难于缩短,费用依然居高不下。
80年代软件工程推行并不顺畅,一些民间开发小系统的制售商急于寻求新路。
Smaltalk-80带来的面对象思想为软件技术发展带来了生机。
于是,80年代中期出现了一批OO语言,几乎所有老语言都作了面向对象改造。
不仅如此,数据库、分布式协作计算、多媒体技术、软件工程工具的集成,甚至计算机硬件都采用OO技术。
OO软件开发方法学改变了传统软件开发模式。
90年代OO技术为各大公司、各种高技术软件接受,并走向工业化、规范化、主流化的途径,其影响至今尚无消减迹象。
学习面向对象语言和技术,最正宗、最有效当从Smalltalk语言开始。
我们首先接受它原有的新范型,与传统过程—模块式大不相同的软件构建思路,再去观察各种技术如何引入、结合OO技术,就会清晰得多。
本章第一、二节介绍原理和实现技术;第三节总结面向对象的基本特征及对应的代表语言;第四、五节分别介绍两个重要的面向对象语言Ada95和Eiffel.
10.1 Smalltalk语言
对象的思想最早源于人工智能研究,60年代末描述智能对象的帧(frame)即封装了许多槽(slot),槽既可以是属性(数据)也可以是行为(操作)和约束。
但最早见诸文献是sketchpad 提到的OO图形学(1963)。
60年代挪威的Dahl和Nyard为模拟系统研制了SIMULA-67语言,首先提出封装的类和动态生成实例对象的概念。
60年代末,美国犹他大学Alan Kay在FLEX项目中为改善个人计算环境,研制窗口菜单的动态生成和交互时,想到了SIMULA的类和对象。
由于受到当时软件限制,其成果未推广。
70年代初他到Xerox公司PaloAlto研究中心参加了Dynabook项目。
该项目的硬件是Star(个人机的前驱)软件是Smalltalk,使用键盘、鼠标操纵图符、窗口、菜单,这在当时是开创性的。
1972年Dan Ingalls完成Smalltalk-72第一个实用版,以后又经过-76-80两次改进,Smalltalk-80成为向外发行的正式版本。
由于Smalltalk必须在专用机器和环境上运行,它的全新编程范型,以及它的小型系统目标,没有得到很快的推广。
但它第一个正式提出“面向对象”完整的概念,在软件界产生深远的影响。
10.1.1 Smalltalk系统
Smalltalk-80是专用机上的语言,只是在它成名之后才有一般操作系统(Unix,OS2)上的版本。
当时Smalltalk系统有四个组成:
·语言核心(Kernel) 规定了Smalltalk-80的语法和语义,它是交互式、无类型的、编译—解释执行的程序设计语言。
·程序设计系统即Smalltalk程序设计支持环境,包括它的界面工具软件和类库支持。
主要是类库,它的类库既支持系统(如解释器就是一个类)也支持应用(提供一组预定义的类)都挂在基类Object为根的类继承树之下。
·程序设计范型(Paradigm) 由于OO程序设计和传统过程语言的程序设计在当时差别较大,它在类这一级设计程序,且以派生新类重用老类为主。
程序中的对象向类对象发消息,可动态生成实例对象。
它所提供的整套设计方法比较新颖。
·用户界面模型(User Interface Model) Smalltalk系统的哲学是用户在终端上以鼠标、键盘、菜单、图符完成应用程序的编辑、修改、运行。
是“用户友好”,以图文并茂的图形用户界面简化使用的先行者。
以下先介绍用户界面模型,再介绍语言核心和程序设计范型,最后给出一完整Smalltalk程序。
10.1.2 用户界面模型
Smalltalk的窗口叫视图(View),是多任务可复盖的窗口,如图10-1所示,每个窗口都有可弹出的菜单及子菜单。
用鼠标选择菜单选项即可操作该窗口。
有以下标准窗口:
图10-1 Smalltalk标准视图(窗口)
·系统工作空间(System WorkSpace)
是一特殊工作空间,提供编辑、求值、文件访问、系统查询。
使用各种消息表达式以及从故障恢复的功能表达式。
·工作空间(WorkSpace)
从系统菜单中可以弹出任意个工作空间,用户在此编辑、修改(切割与粘贴)程序正文,运行、调试、显示结果。
·系统副本(System Transcript)
是一个特殊的工作空间,其职能是正文收集器,它有一组全局变量,记录用户当前调试的类,当其它机制出故障时,它可以得到反馈的另一拷贝。
·项目(Project)
项目窗口用于组织项目。
一个项目窗口创建的变量在另一个项目中可以改变,项目按树形继承组织,子项目完成父项目特定的功能。
工作空间开发的正文可纳入某个项目窗口内。
是多任务管理机制。
·两种图形编辑窗(Form和Bit)
Smalltalk有面向图形的用户界面,用户可以在位编辑器(Bit Editor)之下给出位模式图形,也可以用画笔(Pen)和表达式画出位模式图形,得到一图形块。
图形块(屏上一个块区域)在Form Editor(格式编辑器)窗内操纵,编出更为复杂的图。
·系统浏览器(System Browser)窗
Smalltalk程序开发是基于类派生新类,这种环境必须提供浏览器窗口,以便用户浏览系统类库。
系统浏览器窗口有五个子窗和两个菜单项(标以Class和Instance),如图10-2所示:
图10-2 Smalltalk的浏览窗
Smalltalk的类按分类组织,浏览时先查第一个分类子窗,子窗中都是下拉式菜单,每选定一项分类,正文框中就显示该项的正文模板。
该项(分类)中的成员立即显示在相邻的子窗(类名菜单)中。
第二个子窗下的Instance和Class选项因正文框中显示所选类名项的程序正文模板时,发向实例和类的消息不同而设。
选定类名项后,该类名中的消息分类立即在其右邻子窗显示。
相应的该类的模板示于正文框。
同样,选定消息分类子窗中的选项后,在该选项
下的所有消息选择子,在最右子框中列出。
与消息分类选项对应的正文模板于正文框中显示。
最后,选定消息选择子则与其对应的方法显示于正文框,程序员即可按给定模板写出程序(在工作空间中)。
每个子窗都有操作菜单(如运行(doit),打印(printit),复制(copy),切割(cut),粘贴(paste)……)和本子窗专用菜单(如类名子窗中,有file out,printout,spawn,spawn hierarchy,hierarchy,dtfinition,comnent protocols,inst var refs,class var refs,rename,remove)。
用户就是按浏览窗中显示的模板填写程序。
10.1.3 语言核心
Smalltalk语言核心非常小,只提供表达对象、类、实例、消息/方法的表达式的语法:
(1) 保留字
Smalltalk的保留字只有五个nil,true,false,self,super,前三个是常值,后两个是伪变量,其值根据上下文,不能像变量那样任意赋值。
true,false,nil也是同名类的唯一实例,语义显然。
self,super是在写方法定义时实例对象不在现场的代名词,都是消息的接受者。
self是本类的某个实例,super是本类的直接超类的某个实例。
(2) 字面量
Smalltalk提供五个类(Character,Number,String,Symbol,Array)的字面量实例,它们各有自己的子类,如Number子类有Integer,Float,Fraction。
·字符字面量所有ASCII字符集前冠以$。
·数字面量类似其它语言的整、浮点、分数。
也有2,8,16进制表示,如2rlll,16rFF.C,以及复数22.6+j8r22和虚数j22.9(即22.9i)。
·符号字面量标识符、双目选择子、关键字选择子前冠以‘#’,如:
#aSymbol 标识符
# * 双目选择子
#at:put:关键字选择子
·数组字面量在(……)界定数组前冠以‘#’
(3) 限定符和特殊符号
不包括算术、比较运算符(它们在Object,Number类中定义),以下符号不得重定义。
" 注释限定符
' 串限定符
$字符字面量的前缀
# 符号和数组的前缀
#( ) 数组限定符
,并运算符
;消息分隔符
:关键字消息终止符,块参数前缀
|临时变量限定符,块参数分隔
:=或←赋值号(分别于不同的Smalltalk版本)
↑对象前缀表示该对象的返回值
[ ] 块限定符
( ) {} 优先控制符
(4) 变量
标识符作变量名,约定第一字符小写用于实例,大写用于类,标识符的假德文写法影响
至今,如isFalseGerman 。
·实例变量 私有于一个类的一个实例,且只能由该类及其子类的实例方法访问。
·类变量 一个类及其子类的所有实例可共享的变量。
该类的类方法和该类及其子类的实例
方法均可访问。
·临时变量 私有于定义它的方法,仅当所在方法成活才存在。
·全局变量 Smalltalk 系统中所有方法均可访问的变量。
所有类名均为全局变量,系统字
典Smalltalk 查询所有全局变量。
·汇聚变量(Pool Variables) 是仅能由定义为汇聚字典的一些类访问的全局变量。
·参数 是定义在方法中消息选择子带的对象,私有于方法。
(5) 消息表达式与语句
Smalltalk 是基于表达式的语言,‘语句’并不重要,只是多个顺序表达式用‘.’隔开
称语句。
消息表达式的一般格式是:
对象 选择子 参数
选择子(selector) 带着参数向对象发消息,此对象叫做接受子(receiver)。
Smalltalk
的消息表达式有三种:
·单目的 不带参数
tree class 消息class 发向tree ,得到tree 的类
0.3 sin 消息sin 发向0.3,得sin(0.3)
Array new 消息new 发向Array ,创建一Array 的实例
·双目的
3+4 消息‘+’带参数4发向对象3,得对象7
100@ 50 消息‘@’带参数50发向对象100,得(100,50)
(sum/count) * reserve amount
双目,括号优先 单目优先
双目
消息选择子‘/
’带参数count 发向sum 得一对象(总数的几分之一),消息选择子amount 发
向对象reserve 得一对象(储金数额)作为参数,由选择子‘*’带着发向对象‘总数的几分之
一’,得一对象(储金数)。
·关键字消息表达式
用关键字(带有‘:’的选择子)描述的双目表达式,也是自左至右释义。
关键字虽非保留
字,一旦定义不得改动,且惟一:
anArray at :3 put:100
finances totalSpentOn :‘food ’
前者释义:选择子‘at:’带参数3发向对象anArray,得对象(数组第3元素)。
接着选择子‘put:’带参数100发向第3元素对象,使之有值100。
后者释义:用于食物的总金额。
·赋值变量在不同时间可赋以不同对象,任何表达式加上赋值前缀‘←’(有的系统是‘:=’)即可将表达式的值束定到左边对象上:
quantity←19.
name←‘chapter 1‘.
foo ← array at:4. “数组第4元素与‘foo’同名”
BicPen←Pen new home;turn:89。
最后一个赋值是:新创一个Pen类的实例在起始处(home),‘;’是级联关键字表达式,省写接受子,相当于Pen turn:89(画笔转89度)。
做完之后束定于BicPen。
即画笔实例BicPen 被创建于起始位置并转89°。
·块表达式
括在[]中的上述四种表达式。
块还可以带一到多个参数(前缀以‘:’),并用‘|’与右边表达式隔开,如:
[:x:y|BicPen goto:x@y]
意即将BicPen移到x ╳y处,此时x,y座标是参数化的,如写:
[:x:y|BicPen goto:x@y] value:100 value:250
相当于:
BicPen goto 100@ 250
后面两参数置换x,y并按选择子value:操作。
整个块表达式也是一个接受子对象。
块表达式一般表达一组可延迟执行的动作,例如:
|aBlock|
aBlock←['This is a String' displayAt:500@ 500].
Display white.
aBlock value
aBlock是一临时变量。
第一语句的块不完成赋值束定。
先执行第二语句。
使Display(即在屏上)对象显示白底,待第三语句执行(求aBlock的值)时,块表达式才执行,其值是将串显示在屏中(500,500)起始的位置上。
(6) 控制结构
有条件选择(conditional selection)和条件重复(condition repetition),由关键字识别:
条件选择一般形式是:
布尔子表达式
ifTrue:[‘真’块执行]
ifFalse:[‘假’块执行] “可以不出现”
如:number<0
ifTrue:[absValue←number negated]
ifFalse:[absValue←number]
执行是:‘<’选择子将数0发向对象number返回一布尔对象,若其为‘真’执行‘真’块(上例为一赋值表达式),否则‘假’块。
同样,条件重复一般形式是:
[布尔块表达式]
whileTrue:|wlieFalse:[重复块]
如:[index>listSize]
whileFalse:[list at:index put:0.
index ←index + 1 ]
每次对布尔块表达式求值,若为‘假’对象执行‘假’块直至布尔块表达式求值为‘真’。
(7) 消息/方法
方法(method)是消息的实现,是静态书写的消息(message),方法描述对象如何实施其操作,方法的一般形式是:
消息模式 | 临时变量 | 语句组
单目选择子,双目选择子带参数,关键字选择子带参数,连续的关键字选择子带参数都可以是消息模式。
以一队竖杠( | | )限定的变量集合均为临时变量,临时变量可出现在语句组之中:
newAt:initialLocation|newBox|
newBox←self new.
newBox setLoc:initialLocation tilt:0 size:100 scribe:pen new.
newBox show.
↑ newBox
消息模式是带参数initialLocation的关键字选择子newAt:,临时变量newBox。
方法体中第一句self指本消息要发向本消息所在的类,本类接受new消息生成一实例对象赋给newBox。
第二句是newBox接受后面一串连续的关键字表达式发来的消息,这里setLoc:tilt:size:scribe:带的都是实参,它要找出与之匹配的方法,计算后的对象initialLocation作为参数随setLoc:发向newBox. 第四句是显示结果(在屏幕上,如何show也要找匹配),第五句有左‘↑’的表达式返回表达式(本例为对象)求值后的当前值。
如果在这个类Box中还定义了实例方法:
setLoc:newLoc tilt:newTilt size:newSize seribe:newScribe||
Loc←newLoc. titl←newTilt.
size←newSize. scribe← new Scribe
则上一方法体中第二句的消息就和这个消息模式匹配。
其结果是Box的实例对象newBox,其属性Loc有值initialLocation,tilt值为0,size值为100,自备的画笔scribe已由类Pen 生成(即Pen的新实例)。
10.1.4 Smalltalk文件系统与虚机
Smalltalk语言核心只提供表达式、语句、方法、控制结构语法。
如何写出OO程序和系统如何支持程序设计见后文,本节先说Smalltalk的程序执行。
Smalltalk是编译—解释执行的,Smalltalk源程序经编译器得到虚映象(Virtual image),虚映象由字节代码中间语言编写,由Smalltalk虚机解释执行。
相应的文件系统管理三种文件:源文件、变更文件、映象文件。
源文件是共享的以便多个用户浏览。
如果用户有了更改,使用时,不宜立即施于源文件,而是作为变更文件为用户私藏。
变更文件上有关于用户使用更改的登录。
映象文件是被解释执行的文件。
由于Smalltalk是交互式的,被编译的方法在执行期间出了问题要反映到源程序,则要对映象文件施行反编译(decompliation)得到源程序(但注释和临时变量、形参有丢失)。
Smalltalk的虚机是一个软件,它有三个功能部分:
·负责存储管理器
·虚映象解释器
·基本例程用汇编码写出的底层方法实现,包括输入/出、整数算术,数组下标索引,屏幕图形的基本操作等,其目的是为了改善性能。
存储管理器负责Smalltalk对象的存储管理。
实现数据隐藏和抽象数据类型的管理。
其实现方法本章10.2节再作介绍,其他模块(或对象)对存入的对象仅有的操作是:·取出一个对象的类
·存取对象的各属性(字段)
·创建新对象
存储管理器还要负责无用单元收集并管理自由空间。
无用单元回收一般用引用计数法。
每当建立引用,该对象标志位置‖1‖,即该对象可访问。
每当撤销引用的指针或束定用的常指针,标志位置‖0‖,即该对象不可访问。
当自由分配空间耗尽,则作无用单元收集,将置‖0‖的空间列入自由表。
虚映象的中间码文件以堆栈作为虚拟机模型设计代码。
解释器逐条按代码(其形式如图10-4所示)压、弹栈执行。
和一般解释执行的程序设计语言没什么两样,只是效率更快一些。
Smalltalk系统除虚拟机软件用汇编编写(约6-12KB)外,其它系统软件(包括编译、反编译、排错、编辑、文件系统)均用Smalltalk语言编写(约占整个系统97%),保持了良好的可移植性。
10.1.5 Smalltalk程序设计范型
在Smalltalk系统中什么都是对象,大到一个编译器、解释器,小到一个数(如‘3’)都是对象。
每个对象都有自己的数据存储和施加于这些私有数据上的操作。
数据(即属性)表征了对象的状态,操作在外部激发下操作自己的数据,从而改变了对象的状态。
操作在外部看来如同对象的行为(behavior)。
而同类型对象有同样的行为。
数据属性如用变量描述,就可以用类对象描述同类实例对象。
成为它们的样板和产生它们的工厂。
程序设计在类的层次上进行,由类静态(于工作空间指明向类发出消息)或动态(方法运行时)生成实例对象。
每个对象当接受某消息并执行其方法的消息表达式时都是在向其它对象发消息。
接着在被发消息的接受子对象的类中找消息模式匹配,并执行其方法……
(1)一个简单的Smalltalk程序
例10-1 统计字母出现频率
我们在工作空间中写:
|s f|“定义了两个临时变量”
s←Prompter prompt:‘enter line’ default:‘’.
“s是Prompter的实例,将关键字表达式的结果束定于s”
“意即输入一行字符串,若不输入,则为空串”
f←Bag new. “f是Bag的实例”
s do:[:c|c isLetter ifTure:[f add:c asLowerCase]]
“s在Prompter中找方法do:的模式,块表达式是do:的参数”
↑f “返回f中的值”.
c是块变量,意即从s中拿出某字符,isLetter是消息模式,判c是否字符,若为真执行内块。
内块中f找add:消息模式,从Bag直至上层父类,找到先执行右边子表达式。
c asLowerCase是单目表达式,同样要在Prompter中找asLowerCase匹配,也是不成向
上找。
它返回是“第k个”小写字母,add:把它发送到对象f的第k个位置上并与原数相加。
这个程序一共四句。
如果掀鼠标使菜单项‘doit’工作并输入:
“Smalltalk is a Programming Language for developing soluions to both simple and complex problem.”
则输出的f值是:
7 1 1 2 4 1 5 1 5 1 7 4 4 7 3 3 6 3 2 1
a b c d e f g h i k l m n o p r s t u v
表示‘a’出现7次,‘b’1次,‘d’2次…系统只处理80字符,子串‖omplex problem‖,未计入。
英文字母是本书为说明而加的。
这个程序用到系统的方法很多,我们几乎看不出串是什么数据结构。
实施的算法是什么。
以下是尽可能多地写出算法,并用Paseal程序作对比:
例10-2 字频统计对比程序
(2) 类协议
从上例看来,Smalltalk编程广泛利用以前系统定义的方法。
而方法是在各个类协议(protocol)中定义。
类协议的一般格式是:
单继承,只一个
用于实例对象
用于类对象
充作若干类共享的汇聚字
用于创建实例,并初始化
如上例Array中的方法new:
刻画实例对象行为
如上例中asLowerCase,
at:put:, isLetter 是对象
s,f,c的方法。
显然在设计类协议之先首先要利用浏览窗查看类库中已有的类,它有什么变量和方法。
这里有三种情况:
·如果所有类的变量和方法都不合要求,则作类定义时写超类名为Object,继承它的最一般操作,如new,at:等,其它全由程序员设计。
·如果有一个类很接近你需要的类,则以它为超类,增、删、派生类的变量和方法。
对于‘删去’的变量和方法是以同名变量和方法‘覆盖’,重新定义或置空(动作)。
·如果一个类完全满足你的需要,则在工作窗如同例10-1,直接向它发消息,生成实例并初始化,并将它束定到实例变量名上。
Smalltalk的程序设计除了作类协议而外,就是刻画实例对象如何接受消息,其示意图如图10-2。
运行时di1,di2,ai1,ai2,ci1,ci2,ci3,动态生成,并相互发消息。
接受消息后,在自己所属类的消息模式中找匹配,若找不到找父类,直至Object。
找到匹配的方法后作行形实参数结合执行方法体,执行中又有子表达式发消息,再找匹配继续执行...
图10-3 Smalltalk程序示意图
(3) 一个完整的Smalltalk程序
例10-3 家庭财务帐目
建立全部流水帐类,直接挂在Object上
class name FinancialHistory
superclass Object
instance variable names 'caseOnHand incomes expenditures'
category 'Financial Tools'
class method
initialBalance:amount||“建立流水帐本初始为amount(元)”
↑super new setinitialBalance:amount.
new ||“建立流水帐本初始为0(元)”
↑super new setinitialBalance:0 “这是两个构造子”
instance method
receive:amount from:source ||
incomes at:source put:(self total ReceivedFrom:source) + amount.
―从来源source接收到的钱数‖
cashOnHand←cashOnHand + amount. ―因而手头现金增加‖
incomes changed
spend:amount for:reason ||―为事由reason支付的钱数‖,
expenditures at:reason put:(self totalSpentFor:reason) + amount. cashOnHand← cashOnHand - amount. ‖因而手头现金减少‖
expenditures changed
CashOnHand||“回答当前手头现金”
↑ cashOnHand
expenditures ||“回答支出细目”
↑ expenditures
incomes ||“回答收入细目”
↑ incomes
totalReceiveFrom:source ||“回答自source收钱总数”
(incomes includesKey:source)
ifTrue:[↑incomes at:source]
ifFalse:[↑0]
totalSpentFor:reason ||“回答在reason项上总支出”
(expenditures includesKey:reason)
ifTrue:[↑expenditures at:reason]
ifFalse:[↑0]
private
setlnitialBalance:amount||“实例变量初始化”
cashOnHand←amount.
incomes←Dictionary new.
expenditures←Dictionary new
有了以上FinancialHistory类协议,则可创建一实例HouseholdFinances(家庭财务)并记录收支:
Smalltalk at:# HouseholdFinances put:nil.
HouseholdFinances←FinancealHistory initialBalance:1560
HouseholdFinances spend: 700 for:'rent'.
NouseholdFinances spend: 78.53 for :'food'.
HouseholdFinances receive:820 from:'pay'.
HouseholdFinances receive:22.15 from:'interest'.
HouseholdFinances spend: 135.65 for:'utilities'.
HouseholdFinances spend: 146.14 for:'food'.
表达式中HouseholdFinances是一全程变量,先向FinancialHistory发创建初帐的消息,将返回对象赋于全程量HouseholdFinances. 完成以上表达式,随时可查询“手头现金”,“收入帐目”,“支出帐目”。
程序中includeskey:,at:put:,changed是继承自Object类的方法。
Dictionary是系统提供的字典类。
catagory是分类,为浏览归类存放,查询时,按类名,分类名均可。
10.1.6 Smalltalk程序设计系统
在Smalltalk中,系统支持程序也是作为类挂在Object之下,包括算术运算、数据和控制结构的实现、输入/出、随机数生成器等。
还有一些类是辅助程序设计过程的,语法分析器、编译器、解释器、反编译器这些对象的方法都有源代码,目标码两种形式。
还有一些对象表示类和方法的结构,以便程序员追踪系统。
还有将方法和向其发消息的对象联结起来的对象,这些对象统称环境(contexts)类似其他语言实现中的堆栈帧和活动记录。
Smalltalk的窗口、菜单、以及可视信息均以位模式对象表示,并提供编辑器对象,和外部介质的通信,主要是磁盘文件系统。
对象和字典(数组)都作为单独的文件,以便通信网络使用。
最基本的类库如下示:
Object
Magnitude Stream
Character PositionableStream
Data Read Stream
Time WriteStream
Number ReadwriteStream
Float ExternalStream* Fraction FileStream
Integer Random
LargeNegativeInteger File
Large PositiveInteger FileDirectory
Smallinteger FilePage
Lookupkey UndefinedObject
Association Boolean
Link False
Process True
Collection ProcessorScheduler
SequenceableCollection Delay
LinkedList SharedQueue
Semaphore Behavior
ArrayedCollection ClassDesrcription
Array Class
Bitmap MetaClass
DisplayBitmap Point
RunArray Rectangle
String BitBlt
Symbol CharacterScanner
Text Pen
ByteArray Display Object
Interval Display Medium
Ordered Collection Form
SortedCollection Cursor
Bag DisplayScreen
MappedCollection InfiniteForm
Set OpaqueForm
Dietionary Path
Identity Dietionary Arc
Circle
Curve
Line
LinearFit
Spline
此外,支持浏览、巡视、表示语法错,以及编译、语法分析、扫描等等还有20余个类及
子类。
最后还有一个追踪器,追踪程序的新版本:
SystemTracer
这些类库支持的类今天看来和C++,Java,ada-95非常类似,在当时的确是非常不习惯的。
许多程序员不愿去记忆它并产生抵触情绪,一个类相当于一个文件,类库以树状文件目录实现。
10.2 Smalltalk的对象、类、方法的实现
Smalltalk的源程序,即工作空间中写的类协议和消息指令,经编译生成中间代码,中间代码只对类中各方法体生成。
类、实例对象、活动记录分别存放。
全靠常指针联系,方法匹配靠内部指针变量动态束定。
匹配要快速搜索消息模式,找到后把中间码压入解释执行栈,逐一弹出执行。
(1) 类的存储
定义了类协议之后。
编译时将类对象(设为Box)分配存储并填上中间代码,其格式如下图:
长度
所属分类
类名
超类名
实例变量
类方法
实例方法
图10-4 Smalltalk类协议的存储实现
Box类表示为8个单元,除第一个填本类协议的长度外其它6个全是指针,指向定义内容,内容除关键字之外(如class)均以串形式存放。
类协议最后一项“实例变量数”填4(Box例子中的个数),是为了在解释执行中分配实例存储快一些,不必每次数“空白隔开的串”。
“类方法”和“实例方法”指向“消息字典”,每条消息都有三个指针域:指向消息模式、方法体、消息源代码。
方法体是中间代码形式,语义是压栈、弹栈、送数操作。
实现的是它所指向的方法体的源代码(也以串形式),方法源代码是为了窗口显示而保留的。
(2) 实例对象的存储
实例对象只存放数据,其存储格式如下图:
图10-5 Smalltalk的实例对象存储实现
图中b1,b2是Box类的两个实例,他们指向的表中第一列是为了说明才加上的,他们只放实例变量的值。
所属分类指向Box,而Box又是指针指向自己的存储片。
实例b1存放直接值b2的loc是一点的坐标,则其指针指向Point类的实例,x,y束定于具体值。
Scrilble 描述画笔抬、落、转向的“枚举”变量。
类似的复合数据结构,全按b2形式扩充。
(3) 活动记录
方法每次执行如同过程语言的过程调用,执行一个展开的堆栈帧。
堆栈帧按活动记录描述的数据展开。
活动记录一般分为三部分:
·环境部分:方法执行用到的上下文:分局部local和非局部non-local两部分。
·指令部分:方法执行的指令。
·发送者部分:消息发送者。
活动记录如下图所示:
图10-6 活动记录示意图
其中‖静态链‖指向本方法执行中要用到的实例变量的值(只能到该实例中去找)。
实例和类、超类的连系如同图10-4。
指令部中并不放执行指令, 指令仍在类和超类中, 此处只放方法头指针和特殊指令相对位移。
发送者部的动态链, 连接“调用”本方法的(实例)对象。
活动记录是方法执行中所有相关信息的总索引图。
10.3 面向对象的基本特征
面向对象是在传统语言和软件技术基础上发展起来的: 结构化程序表达导致了对封装、。