编辑“︁
Modula-3
”︁(章节)
跳转到导航
跳转到搜索
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
===对象类型=== 一个[[对象 (计算机科学)|对象]]要么是<code>[[空指针|NIL]]</code>,要么是到有配对的[[方法 (计算机科学)|方法]]套件的一个数据[[记录]]的[[参照|引用]],方法套件是接受这个对象作为第一个实际参数的那些[[子程序|过程]]的一个记录。这个数据记录可以包含经由对象类型的[[子类型]]介入的增加字段,这个套件可以包含经由子类型介入的增加方法。对象[[赋值语句|赋值]]是引用赋值。要复制一个对象的数据记录到另一个对象,这些字段必须单独的赋值。 Modula-3意图保持采用[[对象 (计算机科学)|对象]]这个最简单的术语,而非在其他面向对象语言中对应的术语[[类 (计算机科学)|类]]。对象类型声明采用如下形式: <syntaxhighlight lang="objectpascal"> TYPE T = ST OBJECT Fields METHODS Methods OVERRIDES Overrides END </syntaxhighlight> 这里的<code>ST</code>是可选的[[子类型|超类型]],如果省略则缺省为<code>ROOT</code>,<code>Fields</code>是完全如同记录类型那样的字段声明的一个列表,<code>Methods</code>是方法声明的一个列表,而<code>Overrides</code>是方法覆盖的一个列表。在字段和方法声明中介入的名字,必须相互不同,并且不同于在覆盖声明中的名字。<code>T</code>的字段构成自<code>ST</code>的字段和随后的新声明的字段。<code>T</code>的方法构成自经过<code>OVERRIDES</code>中的覆盖修改的<code>ST</code>的方法,和随后的<code>METHODS</code>中声明的方法。<code>T</code>有着同<code>ST</code>一样的引用类。 关键字<code>OBJECT</code>可选的可以前导上<code>BRANDED</code>或<code>BRANDED b</code>来给对象加铭牌,使之唯一而避免结构等价,这里的<code>b</code>是文本常量。其含义同于非对象的引用类型,<code>b</code>被省略时,系统自动生成唯一性的一个字符串。 方法声明有如下形式:<code>m sig := proc</code>,这里的<code>m</code>是个标识符,<code>sig</code>是过程[[类型签名|签名]],而<code>proc</code>是顶层过程常量。方法声明指定了<code>T</code>的方法<code>m</code>有签名<code>sig</code>和值<code>proc</code>。如果省略了<code>:= proc</code>假定它为<code>:= NIL</code>。如果<code>proc</code>非空,它的第一个形式参数必须是缺省的模态<code>VALUE</code>,并有着<code>T</code>的某个超类型的类型(包括且经常是<code>T</code>自身),并且去除了第一个形式参数结果就是<code>sig</code>所含盖的签名。 方法[[方法覆盖|覆盖]](override)有如下形式:<code>m := proc</code>,这里的<code>m</code>是超类型<code>ST</code>的方法的名字,而<code>proc</code>是顶层过程常量。方法覆盖指定了<code>T</code>的方法<code>m</code>是<code>proc</code>,并非指定<code>ST.m</code>。如果<code>proc</code>非空,它的第一个形式参数必须是缺省的模态<code>VALUE</code>,并有着<code>T</code>的某个超类型的类型(包括且经常是<code>T</code>自身),去除了<code>proc</code>第一个形式参数结果就是<code>ST</code>的<code>m</code>方法所含盖的签名。举例说明: <syntaxhighlight lang="objectpascal"> TYPE Super = OBJECT a: INTEGER; METHODS p() END; Sub = Super OBJECT b: INTEGER END; PROCEDURE ProcSuper(self: Super) = ... ; PROCEDURE ProcSub(self: Sub) = ... ; </syntaxhighlight> 这里的过程<code>ProcSuper</code>和<code>ProcSub</code>是类型<code>Super</code>和<code>Sub</code>的对象的<code>p</code>方法的候选值。例如: {| class = wikitable |- style="vertical-align:top" | <syntaxhighlight lang="objectpascal"> TYPE T1 = Sub OBJECT OVERRIDES p := ProcSub END </syntaxhighlight> || <syntaxhighlight lang="objectpascal"> TYPE T2 = Super OBJECT OVERRIDES p := ProcSuper END </syntaxhighlight> |- | 声明了具有<code>Sub</code>数据记录和预期一个<code>Sub</code>的<code>p</code>方法的一个类型。<code>T1</code>是<code>Sub</code>的有效的子类型。 || 声明了具有<code>Super</code>数据记录和预期一个<code>Super</code>的<code>p</code>方法的一个类型。<code>T2</code>是<code>Super</code>的有效的子类型。 |- style="vertical-align:top" | <syntaxhighlight lang="objectpascal"> TYPE T3 = Sub OBJECT OVERRIDES p := ProcSuper END </syntaxhighlight> || <syntaxhighlight lang="objectpascal"> TYPE T4 = Super OBJECT OVERRIDES p := ProcSub END </syntaxhighlight> |- | 声明了具有<code>Sub</code>数据记录和预期一个<code>Super</code>的<code>p</code>方法的一个类型。因为所有<code>Sub</code>都是<code>Super</code>,这个方法不挑剔要放入的对象。 || 尝试声明具有<code>Super</code>数据记录和预期一个<code>Sub</code>的<code>p</code>方法的一个类型,因为不是所有<code>Super</code>都是<code>Sub</code>,这个方法很挑剔要放入的对象。<code>T4</code>的声明是个静态错误。 |} 如果<code>T</code>是对象类型或到记录的引用,<code>NEW(T)</code>操作有如下形式:{{code|2="modula2"|1=NEW(T, Bindings)}},这里的<code>Bindings</code>是用来初始化新字段的关键字绑定的一个列表,不允许位置绑定。每个绑定<code>f := v</code>将字段<code>f</code>初始化为值<code>v</code>。如果<code>T</code>是对象类型,则<code>Bindings</code>还可以包括形如<code>m := P</code>的方法覆盖,这里的<code>m</code>是<code>T</code>的一个方法而<code>P</code>是一个顶层过程常量。{{code|2="modula2"|1=NEW(T, m := P)}}是{{code|2="objectpascal"|1=NEW(T OBJECT OVERRIDES m := P END)}}的[[语法糖]]。 如果<code>o</code>是一个对象,则<code>o.f</code>指示在<code>o</code>的数据记录中名为<code>f</code>的数据字段。<code>o.f</code>是可写的指定式,它的类型是这个字段的所声明的类型。如果<code>m</code>是<code>o</code>方法之一,以<code>o.m(Bindings)</code>形式的过程调用,指示执行<code>o</code>的<code>m</code>方法,这等价于:<code>(o的m方法) (o, Bindings)</code>。 如果<code>T</code>是对象类型而<code>m</code>是<code>T</code>的方法的名字之一,则<code>T.m</code>指示<code>T</code>的<code>m</code>方法。它的过程类型的第一个实际参数有类型<code>T</code>,而第一个实际参数对应的形式参数名字是未指定的,因此在调用<code>T.m</code>时,第一个实际参数必须按位置来指定,不能用关键字。这种表示法便于子类型方法调用它的某个超类型的对应方法。 在子类型中的字段或方法遮盖(mask)了在超类型中的任何同名的字段或方法。要访问被遮盖的字段,使用类型运算<code>NARROW(x, T)</code>来将子类型变量当作超类型的成员,这里的<code>T</code>必须是对象类型或有跟踪的引用类型,而<code>x</code>必须可赋值给<code>T</code>。<code>NARROW(x, T): T</code>在检查了<code>x</code>是<code>T</code>一个成员之后返回<code>x</code>,如果检查失败则发生运行时间错误。 下面的例子展示了在声明新方法和覆盖现存方法之间的不同,首先声明如下: <syntaxhighlight lang="objectpascal"> TYPE Super = OBJECT METHODS m() := ProcSuper END; SubOverridden = Super OBJECT OVERRIDES m := ProcSub END; SubExtended = Super OBJECT METHODS m() := ProcSub END; VAR a := NEW(Super); b := NEW(SubOverridden); c := NEW(SubExtended); </syntaxhighlight> 然后可以用<code>a.m()</code>激活<code>ProcSuper(a)</code>,用<code>b.m()</code>激活<code>ProcSub(b)</code>,用<code>c.m()</code>激活<code>ProcSub(c)</code>,如此调用在覆盖和扩展之间没有区别。但是扩展的<code>c</code>的方法套件有两个方法,而覆盖的<code>b</code>的方法套件只有一个方法,这可以通过使用<code>NARROW(x, T)</code>将子类型的变量<code>b</code>和<code>c</code>视为超类型<code>Super</code>的成员来披露:<code>NARROW(b, Super).m()</code>激活<code>ProcSub(b)</code>,<code>NARROW(c, Super).m()</code>激活<code>ProcSuper(c)</code>。 对象不能{{le|解引用算符|Dereference operator|解引用}},因为在语言实现中,一个对象变量的静态类型不确定它的数据记录的类型。对象类型确定了关乎数据[[记录]][[字段]]和[[方法 (计算机科学)|方法]]套件的超类型链的前缀的那些类型。 ====实现==== 下面是语言设计者提出的对象的一种可能实现的梗概<ref name="type">{{cite web|url=http://lucacardelli.name/papers/modula3typesystem.a4.pdf|title=The Modula-3 Type System|authors=Luca Cardelli, Jim Donahue, Mick Jordan, Bill Kalsow, Greg Nelson|year=1989|access-date=2021-08-12|archive-date=2021-03-24|archive-url=https://web.archive.org/web/20210324050223/http://lucacardelli.name/Papers/Modula3TypeSystem.A4.pdf}}</ref>,一个对象可以表示为它的数据记录的第一个[[字 (计算机)|字]]的地址。前面的字存储一个对象头部,它包含一个唯一于对象类型的类型代码。这些类型代码是小型整数,对每个对象类型和每个有跟踪的引用类型都有一个代码。在对象头部之前的字,存储到这个对象的方法套件的一个引用。如果这个对象没有方法,这个字可以省略。这还允许对象共享方法套件,这是常见情况。如果<code>o</code>是一个对象,<code>d</code>是它的数据字段之一,而<code>m</code>是它的方法之一,则在这种表示下: {| class="wikitable" |- |<code>o.d</code> || 是 || <code>Mem[o + d]</code> |- |<code>o.m</code> || 是 || <code>Mem[Mem[o – 2] + m]</code> |- |<code>TYPECODE(o)</code> || 是 || <code>Mem[o – 1]</code> |} 这里假定了字段和方法以自然方式表示为[[偏移量]]。进一步的问题是如何高效的测试一个对象<code>o</code>是否有着类型<code>T</code>,这是<code>NARROW()</code>和<code>TYPECASE</code>语句所需要的。<code>NARROW()</code>的最简单实现,是维护一个以类型代码为索引的数组<code>st</code>,<code>st[tc]</code>是其类型代码为<code>tc</code>的对象类型的超类型的类型代码,如果它没有超类型则为<code>NIL</code>。要测试<code>o</code>是否是一个<code>T</code>,使用一个循环来计算<code>T</code>的类型代码是否出现在如下序列之中: <syntaxhighlight lang="modula2"> TYPECODE(o), st[TYPECODE(o)], st[st[TYPECODE(o)]], ... NIL </syntaxhighlight> 这个序列可以称为<code>o</code>的类型的超类型[[路径 (计算机科学)|路径]],而它的长度可称为<code>o</code>的类型的深度。利用上每个类型的深度都是编译时间确定的,因此可以同相应的类型代码一起存储的事实,可以有更快速的<code>NARROW()</code>实现。如果<code>T</code>的类型代码,出现在类型<code>U</code>的超类型路径上,它就该在位置<code>depth(U) - depth(T)</code>上。如果每个类型的超类型路径都是顺序[[数组]],这意味着<code>NARROW()</code>可以用恒定时间实现。因为超类型路径通常不太长,这是一个有吸引力的策略。在不常见的对象类型有非常长的超类型链的情况下,只有这个链的直到某个极大长度的一个前缀,会被顺序的存储。在运行时间,这个深度差如果超出这个链的顺序存储的长度,实现必须回退到[[链表]]。
摘要:
请注意,所有对Local Chinese Wikipedia的贡献均可能会被其他贡献者编辑、修改或删除。如果您不希望您的文字作品被随意编辑,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源(详情请见
Project:著作权
)。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)
导航菜单
个人工具
未登录
讨论
贡献
创建账号
登录
命名空间
页面
讨论
大陆简体
不转换
简体
繁體
大陆简体
香港繁體
澳門繁體
大马简体
新加坡简体
臺灣正體
查看
阅读
编辑
查看历史
更多
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息