管理类方法名的制作方法

文档序号:6406762阅读:182来源:国知局
专利名称:管理类方法名的制作方法
技术领域
本发明通常是与改进面向对象的应用有关,更具体地说是与有效管理类方法名有关的。
在工作站软件开发者中越来越认识到面向对象的程序设计(OOP)是一种重要的新的程序设计技术。对于软件的重复使用和扩展性而言,它提供了扩展的机会,当与传统的软件开发范例相比时,它改进了程序员的生产率。即使如此,面向对象技术至今尚未有效地渗入到主要的商业软件产品中。特别是,操作系统仍不敢放心地利用此项新技术。
如同许多新的程序设计技术一样,OOP概念的早期的表示集中在建立新的语言和工具集中,每一种语言或工具设计成只是利用了某些特殊方面。所谓的纯面向对象语言,如Smalltalk,假设的是一个完整的运行时环境(常常叫做虚拟机器),因为它们的语义学在重要方面偏离了传统的面向过程的系统体系结构。另一方面,混合语言,如C++,需要较少的运行时的支持,但结果常常与提供对象的程序和使用对象的客户程序之间紧密结合。无论什么时候,如果所提供的程序中作了简单的修改的话,则由于提供对象的程序和它们的客户程序之间的紧密结合而常常需要客户程序再编译。这样的系统实例可见美国专利4,885,717;4,953,080和4,989,132。
由于不同的语言和面向对象的工具集强调的是OOP的不同方面,结果软件的实用程序常常限制在这些范围中。例如,一个C++程序员不能很容易地使用在Smalltalk中开发的对象,而一个Smalltalk的程序员也不能有效使用C++的对象。在一种语言中实现的对象和类别不能简单地、容易地用在另一种语言中。不幸的是,当这种情况发生时,OOP的主要优点之一增加代码重用的优点便急剧地消失。实际上,面向对象语言和工具集的界面就成为对互操作性的障碍。
因此,本发明的基本目的是通过把所有命名的表示形式和附加的支持信息收集到单一数据结构的方法来管理类方法的取名,以便改善管理特性。
本发明的这些和其它目的由一种特定的算法的操作来实现,这种算法存放在处理机的存贮器中并使用两台机器。
首先,类方法过程表由系统对象模型(SOM)编译器生成的特定的类过程来初始化。这些过程存放在含有方法定义的文件中。这就使这些过程能够提供对方法名的命名而不用对方法名实施外层的初始化。特殊过程提供的信息借助于类数据结构获得,每当需要此信息时就可通过类方法进行存取。
第二,对于方法的任何附加的支持信息,特别是每种方法在其方法过程表中的偏移被记录在单一的在外部命名的数据结构中。把两台机器结合使用排除了以每种方法为基础的外部名的要求。


图1为按照本发明题目的个人计算机系统的框图;
图2为按照本发明题目的系统对象模型(SOM)数据结构的框图;
图3为按照本发明题目的SOM类数据结构的框图;
图4为按照本发明题目的描述语言的中性对象界面的流程图;
图5为按照本发明题目的描述使用SOM对象的应用程序的连接、加载和执行的流程图;
图6为按照本发明题目的描述新的SOM类的建立的流程图;
图7为按照本发明题目的描述建造新的SOM类的详细的流程图;
图8为按照本发明题目的描述建造新的SOM通用类的对象的详细的流程图;
图9为按照本发明题目的描述建造新的SOM类对象的详细初始化的流程图;
图10为按照本发明题目的描述具有偏移值的SOM数据结构的详细初始化的流程图;
图11为按照本发明题目的描述静态定义类层次的详细父类影子的流程图;
图12为按照本发明题目的描述重调度方法的流程图;
图13为按照本发明题目的描述对于单个公共实例变量而言的在SOM类数据结构中,偏移值的详细初始化的流程图;
图14为按照本发明题目的描述当用重调度存根来将静态方法调用转换成动态方法调用时所发生的详细控制流程的流程图;
图15为按照本发明题目的描述对于类的初始化方法过程表的详细控制流程的流程图。
实际证明在从IBM公司得到的PS/2计算机上驻留的操作系统的上下文中本发明是更可取的。图1描述了代表性的硬件环境,它按照本发明题目图解说明了一个工作站的典型硬件配置,它有一个中央处理器10,例如通常的微处理器,以及一些通过系统总线12互连的其它装置。图1所示的工作站包括随机存取存储器(RAM)14,只读存储器(ROM)16,一个用于将外部设备如磁盘装置20连到总线的输入/输出(I/O)适配器18,一个用于将键盘24,鼠标器26,扬声器28,话筒32及其它用户接口设备例如触摸式屏幕设备(图中未示出)等连到总线的用户接口适配器22,一个将工作站连到数据处理网络的通信适配器34和一个将总线连到显示设备38的显示适配器36。该工作站驻留有OS/2基本操作系统和组成作为工具集而包括本发明的计算机软件。
在开发高质量、可重用代码中,面向对象的程序设计作为一种重要的方法学其本身正在迅速建立中。本发明包括用于开发类库和面向对象程序的一种新系统,该系统叫做系统对象模型(SOM)。本发明还提供了对面向对象程序设计、SOM和对其它面向对象的语言相比较的详细描述,以帮助你理解本发明。
面向对象的程序设计介绍在软件界,面向对象的程序设计是新的发展。面向对象的程序设计语言(OOPL)正用于整个工业界,面向对象的数据库(OODB)开始引起广泛的兴趣,甚至面向对象的设计和分析(OODA)工具正在改变人们设计和模型系统的方式。
面向对象的程序设计与它接近的同类-结构程序设计相比更易理解。两者都企图处理相同的基本问题,以便管理更复杂软件系统的复杂问题。结构程序设计将系统设计成一个功能模型的层次集合。这些模型建成金字塔形,每一层表示系统的较高一级的观察,结构程序设计仿真系统的行为,但对于系统信息模型而言,它只给予很少的指南。
面向对象的程序设计将系统设计成一个协作对象的集合。如同结构程序设计,它企图管理系统合成的状况。然而,面向对象的程序设计在试图管理系统的信息合成方面却与结构程序设计不同。
因为面向对象的程序设计在系统的状况和信息合成方面建立模型,如果系统是较好的“结构化”的话,则系统有助于更好地被组织。由于面向对象的系统组织得较好,所以它们容易理解,排错,维护和发展。组织好的系统也有助于它们对可重新使用的代码进行编码。面向对象的程序设计可以想象在管理信息和状况合成两方面问题,因为它们关系密切。它的基本的组织部分是对象。对象具有某些叫做对象状态的关联数据和叫做对象方法的操作集合。由子程序来实现方法。类是定义对象状态的数据表示的对象和用于支持对象方法的总的描述。
在C语言中面向对象的程序设计在观察SOM以前,让我们考虑一下C语言中的面向对象的程序设计;这将使我们很自然进入SOM的原理中。让我们考虑具有与类属堆栈有关信息的数据结构定义。数据结构包括用于在堆栈结构上操作的一系列功能。当给定了基本堆栈定义之后,在我们程序中将说明该数据结构的多个例子。
下面是C语言中类属堆栈的定义struckstackType{Void*stackArray〔STACK-SIZE〕;
intstackTop;
};
typedefstruckstackTypestack;
下述是类属堆栈功能的定义stack*create();/*分配和初始化一个新堆栈。*/Void*pop(/*将元素弹出堆栈。*/stack*thisstack);
Voidpush(/*压入堆栈。*/
stack*thisstack,void*nextElement);
多数C程序员可以想象这些功能是如何写的。例如,<PUSH()>功能如下所述VoidpusH(stack*thisstack,Void*nextElement){thisstack-stackArray〔thisStack-stackTop〕=nextElement;
thisstack-stackTop++;
}客户程序也可能使用这种堆栈,比方说,建立一个需要解释词的堆栈main(){stack*WordStack;
char*subject=“Emily”;
char*verb=“eats”;
char*object=“icecream”;
char*nextWord;
Wordstack=create();
pusH(Wordstack,object);
pusH(Wordstack,verb);
pusH(Wordstack,subject);
/*…*/while(nextWord=pop(wordstack)){printf(“%s/n”,nextWord);
/*…*/}}该例子可以用来观察面向对象的程序设计。类是一个对象的定义。该定义包括对象的数据元素和它支持的方法。<stack>是类的一个例子。一个堆栈具有两个数据元素(<stackArray>和<stackTop>),且支持三种方法<create()>,<pusH()>,和<pop()>。方法就像一种功能,但是它是用于对一个特指的类的对象的操作。对象是类的一个专门的例子或例示。对象<wordstack>要么是类<stack>的对象,要么是一个堆栈的实例。
每一种方法需要一个对其进行操作的专门对象。该对象叫做目标对象或者有时叫做接受对象。注意,每一种方法(除了<create()>)都将它第一个参数作为目标对象的指针。这是因为一个程序对于一个给定类可能具有多个对象,并且对于类的方法而言,每个对象都是潜在的目标。
这种类型的组织具有三个重要的优点。首先发展了类属的概念,它可在类似概念是合适的其它情况下重新使用。第二,发展了自含代码,在它合并到程序之前,它可以全部进行测试。第三,发展了压缩代码,在这种代码中细节是隐藏的,并且对客户而言是毫无兴趣的。客户程序<main()>除了堆栈的名、它支持的方法和这些方法的界面以外,它不需知道堆栈<stack>类的任意情况。
和C++的比较另一个有益的比较是SOM和最广泛使用的面向对象的程序设计语言C++的比较。SOM和C++有许多类似点。两者都支持类的定义、继承和覆盖方法(在C++中叫做虚拟方法)。两者都支持压缩的概念。但是C++都用于支持独立的程序设计工作,而SOM集中在对商业质量类库的支持。SOM和C++之间多数的不同之处关键在于这个问题。C++类库是依赖于版本的,而SOM类库则是独立于版本的。当一个新的C++类库发行时,即使如果客户代码的修改与公共界面无关时,客户代码仍必须完全重新编译。
C++只是在唯一的一种语言-C++中支持程序设计。而SOM则用于支持多种语言。SOM不是一种语言,而是用于定义、操纵和发行类库的系统。SOM是用于定义类和方法的,但是对于实现方法而言,它让实现者去选择语言,而不必学习一种新的语言的句法。
C++对实现隐芷或压缩而言只是提供最小的支持。
必须发行给客户的C++类的定义典型的是包括了用于专有数据和方法的说明。在SOM中,客户从来不必集中在这些实现的细节。客户只须看只含公共信息的<.SC>文件。C++也提供了有限的方法判定功能,而SOM则提供了几种选择,如偏移方法判定,名字查找判定和调度判定。
SOM和C++间的另一个有趣的不同之处在于它的类的概念上。C++的类的说明非常类似于结构说明。它是一个只有在运行时有意义的无特性的编译期间的程序包。在SOM中,一个对象的类就是对象。类对象本身是另一个类的实例,叫做元类。类对象支持有用方法的宿主,这些方法在C++中没有直接的比较,如<somGetName()>,<somGetParent()>,和<somFindMethod()>。
SOM介绍OS/22.0包括一个中性语言面向对象的程序设计机构,叫做SOM(系统对象模型)。尽管用传统语言写面向对象的程序设计是可能的,如堆栈的例子,但是SOM是专门用来支持新的词形变化表并且可以和过程(非面向对象)语言和面向对象语言一起使用。
面向对象的程序设计的重要需求是代码的可重用性。典型地说,代码的可重用性是通过类库的使用来实现的。今天的库技术局限在于类库总是与专门语言有关的。C++库不能由Smalltalk程序员使用,而Smalltack程序员不能使用C++库。很明显,建立一个中性语言的对象模型是必要的,该模型可以用来建立对于任意程序设计语言,过程的或面向对象的语言能用的类库。
SOM引入了在多数过程语言中缺少的三个重要的特点,它们是压缩、继承和多形(这儿指的是“覆盖判定”)。继承指的是一种技术,它规定了当从另一个类(叫做父类或超类)到增量差时,类(叫做子类)的形状和行为。
压缩指的是隐芷了实现客户的细节。它防止客户在能有害地影响系统的实现中进行修改。例如,在堆栈的例子中没有提供给C代码的保护。尽管客户不需要知道堆栈的内部数据结构,但是没有办法来防止客户看这些实现的细节。我们可以不鼓励,但是不能防止客户写那些使用并可能搀杂内部堆栈数据元素的代码。
继承或类的派生是用于从已经存在的类中开发新的类的一种专门技术。它提供了建立新类的能力,而这些新类是已存在的类的更专门的版本。例如,我们可以建立一个<Debuggablestack>,它象一个<stack>类,但是它支持进一步排错方法,如<peak()>是用于看栈顶部的值,<dump()>是用于打印整个堆栈的列表。
继承也提供了代码的摘录。一,例如,定义<GraduateStudent>和<UnderGraduateStudent>的类可以被摘录到第三个类<student>中。然后,我们定义<GraduateStudent>和<UnderGraduate>这二个类为更专门的类,这二个类都是从公共的父类<Student>中派生的。
继承引入了一些附加的语义学。所说的专门的类可从更普遍的类中派生得到。该普遍的类叫做父类或者有时叫做基类。将专门的类叫做子类或有时叫做派生类。所说的子类继承了它的父类的特点,这意味着任意为父类定义的方法会自动地为子类所定义。于是,由于<GraduateStudent>和<UnderGraduateStudent>二者都是从<Student>派生的所以它们两者都自动获得它们公共的父类中所说明的方法。
覆盖判定指的是所引用的被判定的方法不仅基于方法的名字,而且还基于在类的层次中的类的位置。当我们派生这些类时,这就可以使我们重定义方法。我们可以为<student>定义<printstudentInfo()>方法,然而在<UnderGraduateStudent>和<GraduateStudent>两者中覆盖或重新定义方法。覆盖判定是机遇目标对象的类型来判定的。如果目标对象类型是<Student>,则引用<printstudentInfo()>的<Student>版本。如果目标对象类型是<GraduateStudent>的话,则引用<printstudentInfo()>的<GraduateStudent>版本。
SOM中定义类在SOM中建立类库的过程是一个三步的过程。类的设计者定义该类的界面,实现类的方法,最后是将结果对象代码加载到类库中。客户可以直接使用这些类,或作些修改一适应他们专门的目的或者假如他们自己的完全新的类。
在SOM中,由建立类定义文件来定义一个类。类定义文件名的扩展为“CSC”。在类定义文件的最基本格式中它可以分为下述几个段落1.Include(包括)段该段说明了需要包括的文件,很象C<#include>所指示的。
2.类名和任选项该段定义了类的名字并且说明了各种不同的任选项。
3.父信息该段定义了该类的父类或基类。所有的类必须具有父类。如果一个类不是从任意已存在的类中派生的话,则它的父类是SOM定义的类<SOMobject>,该类的信息在文件<somobj.sc>中。
4.数据段该段说明了这个段的对象所具有的数据元素。根据缺省的值,数据只能由该类的方法来存取。
5.方法段ⅩⅣⅩⅣ该段说明了该类的对象可以响应的方法。根据缺省值,本段中所说明的所有方法对任意类的客户而言都是可以用的。类定义文件<student.csc>描述了一个不能得到的<student>类,并且表示如下classDefinitionfile<student.csc>
include<somobj>
classstudent;
parentsomobject;
datacharid〔16〕;/*学生标识符*/charname〔32〕;/*学生名*/METHODSvooidsetupstudent(char*id,char*name);
-设置新学生,voidprintstudentinfo();
-打印学生信息char*getstudentType();
-返回学生的类型char*getstudentId();
-返回学生的标识符。
如何写方法类方法是在类方法实现文件中实现的。在类定义文件的方法段中定义的每一种方法是需要实现的。可以以提供SOM支持的任意语言来实现它们。在整个规范中,C是用作一种典型语言的。然而,一个普通的技术熟练人员将可以用能够替换的任意程序设计语言来实现。学生类方法实现文件<student.c>表示如下ClassMethodImplementationFile<student.c>
#defineStudent-classsource#include“student.in”StaticvoidSetUpStudent({Student*somself,char*id,char*name){StudentData*somthis=studentGetData(somself);
Strcpy(-id,id);
Strcpy(-name,name);
}StaticVoidPrintstudentInfo(student*somself){StudentData*somthis=StudentGetData(somself);
printf(“Id%s/n”,-id);
printf(“Name%s/n”,-name);
printf(“Type%s/n”,-getStudentType(somself));
}StudentData*somthis=StudentGetData(somself);
Staticchar*type=“student”;
return(type);
}staticchar*getStudentId(student*somself){StudentData*somthis=StudentGetData(somself);
return(-id);
}注意,本方法的代码看来和标准的C很类似。首先,每个方法将对目标对象的指针C<SOMSELF>作为它的第一个参数。该参数在类定义文件中是隐含的,但在方法实现中是显式的。第二,每个方法是以一个行设置名字为<somThis>的内部变量开始的,这个内部变量是由SOM标题文件中定义的宏来使用的。第三,目标对象的数据元素的名字前面是下横线字符“-”。下横线的名字表示的好似在类标题文件中定义的C语言的宏。第四,通过在方法名前放一个下横线“-”来引用方法。该下横线的名字表示用语信息判定的宏并且是程序员不必了解该过程的细节。
每个方法的第一个参数总是是一个对目标对象的指针。这种情况将在下面方法<printStudentInfor()>中加以说明,该方法引用了它的目标对象中的方法<getStudentType)()>。
生成<Student.c>的SOM编译程序#defineStudent-Class-Source#include“student.in”staticvoidsetUpStudent(Student*somSelf,char*id,char*name){StudentData*somthis=StudentGetData(somself);
}staticvoidprintStudentInfo(Student*somSelf){StudentData*somthis=StudentGetData(somself);
}/*……对于其它方法等等。*/使用SOM的机构这儿有一组与下面要讨论的每一个类一起引用的文件。这些文件具有不同的扩展名,但是它们全都有与类定义文件相同的文件名,在我们的例子中为<student>。下面来描述这些文件。
Student类文件<student.csc>-正如前面所述的,这是类定义文件。
<student.csc>-这是类定义文件的子集。它包括了从<.csc>文件的所有信息,而<.csc>文件是公共的,并包括了公共元素的注解。对于Student例子而言,<student.sc>包括了除了数据段以外的全部<student.sc>的信息。该文件是由SOM编译程序建立的。<student.h>-这是一个有效的C标题文件,它包含了对于引用公共方法和存取类的公共数据元素所必须的宏。该文件将包括在类的客户文件在,并且它是由SOM编译程序建立的。
<student.ih>类似于<student.h>,但是它包含了实现方法所需的附加信息。这是<.h>文件的实现者的版本,并且必须包括在类方法实现文件中。该文件是由SOM编译程序建立的,并且不应加以编辑。<student.c>包含了本方法的实现。开始是由SOM编译程序建立的,然而由类实现者加以更新。
从其它类中建立SOM类当为其它类建立块时,有两种方法来使用类,它们是派生(或继承)和建造。
派生在本例中<Graduatestudent>是从它的基、或父类<student>中派生而来的。派生类自动拾取基类的全部特性。一个派生类可以通过对新的方法的定义和实现来加上新的功能。派生类也可重新定义它的基类的方法及叫做覆盖的过程。例如,<Graduatesstudent>将<setUpgGraduateStudent()>加到那些从<student>继承来的方法。它覆盖了两个其它的继承方法-<printStudentInfo()>和<getstudentType()>。它从基类<student>中继承但没有修改<setUpstudent()>和<getstudentId()>。
对于<Graduatestudent>和<graduate.csc>而言,类定义文件表示如下ClassDefinitionFile<graduate.csc>
include<student.sc>
classGraduateStudent;
parentStudent;
datacharthesis〔128〕;/*thesis标题*/chardegree〔16〕;/*研究生学位类型*/*/
methodsOverrideprintstudentInfo;
Overridegetstudenttype;
VoidsetUpGraduateStudent(char*id,char*name,char*thesis,char*degree);
方法实现文件<graduate.c>如下所示ClassMethodImplementationFile<graduate.c>
#defineGraduateStudent-class-source#include“graduate.ih”StaticvoidprintStudentInfo(GraduateStudent*somSelf){GraduateStudentData*somthis=GraduateStudentGetData(somself);
patent-PrintstudentInfo(somself)printf(“Thesis%s/n”,-thesis);
printf(“Degree%s/n”,-degree);
}StaticChargetStudentType(Graduatestudent)*somself){
StaticCharsetUpGraduateStudent(GraduateStudent*somself,char*id,char*name,char*thesis,char*degree){GraduateStudentData*somThis=GraduateStudentGetData(somself);
-setUpstudent(omSelf,id,name);
strcpy(-thesis,thesis);
strcpy(-degree,degree);
}覆盖方法经常需要引用它的父类的原始方法。例如,对于<GraduateStudent>而言,<printstudentInfo()>在打印<GraduateStudent>专门信息以前,首先引用<printstudentInfo()>的<student>版本。对此的句法是“<parent-MethodName>”,因为这可在<printstudentInfo()>方法中见到。
给定的基类可以用于一次以上的派生。类<UnderGraduateStudent>也是从<student>派生来的。类定义文件<undgrad.csc>表示如下classDefinitionFile<undgrad.csc>
include<student.sc>
class
UnderGraduateStudentparentstudent;
datachardata〔16〕;/*毕业日期*/methodsoverrideprintstudentInfo;
overridegetstudentType;
ovidsetUpUnderGraduateStudent(char*id,char*name,char*date);
方法实现文件<undgrad.c>表示如下classMethodImplementationFile<undgrad.c>
#defineUnderGraduateStudent-Class-Source#include“Undgrad.ih”StaticVoidprintStudentInfo(UnderGraduateStudent*somself){UnderGraduateStudentData*somThis=UnderGraduateStudentGetData(somSelf);
parent-printStudentInfo(somSelf);
printf(“GradDate%S/n”,-date);
}staticchar*getstudentType(UnderGraduateStudent*somSelf){staticchar*type=“UnderGraduate”;
return(type);
}staticVoidsetUpUnderGraduatStudent(UnderGraduaduateStudent*somSelf,char*id,char*name,char*date){UnderGraduateStudentData*somThis=UnderGraduateStudentGetData(somSelf);
-setUpStudent(somSelf,id,name);
strcpy(-date,date);
}建立类的第二种技术是建造。建造指的是使用另一个类的类,但是没有经过继承。建造的好例子是类<Course>,它包括了对<student>的指针数组。每个指针有特定学生上课的地址。<Course>是从<student>建造的。对<Cpurse>的类定义文件<Course,csc>表示如下classDefinitionFile<Course.csc>
include<somobj.sc>
classcourse;
parentSOMobject;
datacharcode〔8〕;/*课程代码号*/chartitle〔32〕;/*课程名*/charinstructor〔32〕;/*教课老师*/intcredit;/*信用卡号*/intcapacity;/*最多的座位数*/studentdtList〔20〕;/*已注册的学生*/(注1)(注1原文无*/,你漏打(按语法要求))intenrollment;/*注册学生的数量*/methodsoverridesomInit;
voidsetUpCourse(char*code,char*title,char*instuctor,intcredit,intcapacity);
-建立新的课程。
intaddStudent(student*student);
-该课程注册的学生。
voiddropStudent(char*studentId)-从该课程中退出的学生。
voidprintCourseInfo();
-打印课程信息。
类经常会希望采取专门的步骤来初始化它们要求的数据。<Course>的实例至少必须初始化<enrollment>数据元素,以确保数组的下标在有效状态下开始。当建立新的对象时,总是要调用方法<somInit()>。该方法是从<SOMobject>中继承的,并且当需要对象初始化时,它可以被覆盖。
该例子提示了继承的有趣特点,即在派生和基类之间的“是一个”关系。任意派生的类都可以认为是个基类。我们称一个派生类“是一个”基类。在前面的例子中,任意的<GraduateStudent>“是一个”<student>,并且可以用在任意的我们期望<student>的地方。但及之不正确。基类不是派生的类。<student>不能无条件地认为是<GraduatStudent>。因而,数组<studentList>的元素可以指向任意的<student>,<GraduateStudent>或<UnderGraduateStudent>。
对于<Course>的方法实现文件<course.c>表示如下classMethodImplementationFile<course.c>
#defineCourse-Class-Source#include<student.n>
#include“Course.in”staticVoidsomInit(Course*somSelf){CourseData*somThis=CourseGetData(somSelf);
parent-somInit(somSelf);
Code〔0〕=-title〔0〕=-instructor〔0〕=0;
-Credit=-capacity=-enrollment=0;
}staticVoidsetUpCourse(Course*somSelf,char*code,char*title,char*instructor,intcredit,intcapacity){CourseData*somThis=CourseGetData(somSelf);
strcpy(-code,code);
strcpy(-title,title);
strcpy(-instuctor,instuctor);
-credit=credit;
-capacity=capacity;
}staticintaddStudent(Course*somSelf,Student*student){CourseData*somThis=CourGetData(somSelf);
if(-enrollment>=-capacity)return(-1);
-studentList〔-enro;;ment++〕=student;
return(0);
}staticVoiddropStudent(Course*somSelf,char*studentId){inti;
CourseData*somThis=CourseGetData(somSelf);
for(i=0;i <-enrollment;i++)if(!strcmp(studentId,-getStudentId(-studentList〔i〕))){-enrollment-;
for(i,i<-enrollment;i++)-studentList〔i〕=-studentList〔i+1〕;
return;
}}staticvoidprintCourseInfo(Course*somSelf){inti;
CourseData*somThis=CourseGetData(somSelf);
printf(“%S%S/n”,)Code)-title);
printf(“InstructorName%S/n”,-instructor);
printf(“Credit=%d,Capacity=%d,Enrollment=%d/n/n”,-credit,-capacity,-enrollment);
printf(“STUDENTLIST=/n/n”);
for(i=0;i<-enrollment;i++){-printStudentInfo(-studentList〔i〕);
printf(“/n”);
}}注意特别的方法<printCourseInfo>。该方法全面考虑数组<studentList>,而该十组对每个学生引用方法<printStudentInfo()>。该方法是为<student>的,并且再由<GraduateStudent>和<UnderGraduateStudent>二者覆盖。由于该数组元素可以指向任意的这三个类,因而在编译时间不可能确定目标对象的实际类型是什么,只能确定目标对象是<student>或某个从<student>派生来的类型。由于每个这样的类定义了不同的<printStudentInfo()>方法,因此不可能决定在每个循环过程中将引用这些方法中的哪一个。这全部是在覆盖判定的控制之下。
SOM客户为了理解客户在程序中可能如何使用这四种类,下面在文件<main.c>中给出一个例子。该例子说明了在SOM中对象的实例和建立过程及如何引用方法。
SOMclientcode=<main.c>
#include<student.n>
#include<course.n>
#include<graduate.n>
#include<undgrad.n>
main(){course*course+CourseNew();
GradateStudent*jane=GraduateStudentNew();
UnderGraduateStudent*mark=UnderGraduateStudentNew();
-setUpCourse(Course,“303”,“Compilers”,Dr.DavidJohnson”,3,15);
setUpGraduateStudent(jane,“423438”,“JaneBrown”,“CodeOptimization”,“Ph.D.”);
-setUpUnderGraduateStudent(mark,“399542”,“MarkSmith”,“12/17/92”);
-addStudent(Course,jane);
addStudemt(Course,mark);
printcourseInfo(course);
}用方法<classNameNew()>例示了一个类,对于每个识别的类,该方法是由SOM自动定义的。通过在方法名前置一个下横线“-”来引用方法第一个参数是目标对象。余下的参数描述了该方法所需的附加信息。当运行时,如下所示客户程序给出的输出ClientProgramOutput303CompilersInstructorNameDr.DavidJohnson
Credit=3,Capacity=15,Enrollment=2STUDENTLISTId423538NameJaneBrownTypeGraduateThesisCodeOptimizationDegreePh.D.
Id399542NameMarxSmithTypeUnderGraduateGradDate12/17/92客户程序输出以不同的显示<UnderGraduate>和<GraduateStudent>的方式描述了工作时的覆盖判定。<course>认为它自己具有<student>的数组,并且知道任意的<student>响应<printStudentInfo()>方法。<UnderGraduate>响应的<printStudentInfo()>方法是不同于<GraduateStudent>响应的<printstudentInfo()>方法,因而两种方法给出了不同的输出。
SOM对象模型图2所示为按照发明的基本的SOM数据结构。标号210是一个特定对象的状态数据结构。标号220处的第一个全字是对象方法过程表(标号240)的地址。标号230表示的状态数据结构的余下部分含有关于对象的附加信息。标号240表示的方法过程表含有类对象数据结构245的地址和对于特指的对象250和260的不同方法的地址。在245处的这个方法过程表的地址。由该对象继承的任意方法将具有在存储器中与该方法中所示出现的相同偏移的方法过程地址。在标号240处表示的是祖先类的过程表。上述所指的类是从该祖先类中继承的。
对于两个方法过程而言,在标号250和260处表示的是具有一系列指令的计算机存储器块地址。标号270和280表示的是计算机存储器中的位置,该存储器具有由标号250和260表示的地址所指向的特指的方法过程的一系列指令。
SOM的基类SOM对象模型的多数是由属于基本SOM所支持的部分中的三个类来实现的。这些类描述如下SOMobject-该类是所有SOM类的根类。任意一个类必须出身于SOMobject,它们都继承该类因而也支持有SOMobject定义的方法。SOMobject的方法像任意SOM类的方法一样可以由出身于SOMobject的类所覆盖。
SOMclass-该类是对于所有SOM元素的根元素。元类是实例为类对象的类。SOMclass提供了允许新建立的类对象的方法。SOMclassMgr-该类用于在管理类对象的SOM基程序中建立耽搁对象。
下面来定义三个SOM基类。
SOMobject这是SOM的根类,所有SOM类必须出身于<SOMobject>。<SOMobject>无实例数据,因而没有每个实例从它出身的花费。
Somobject具有下述方法方法SomInit参数SomSelf返回Void描述初始化<self>。因为<Somobject>的实例没有任意的实例数据,因而没有什么初始化而且不必调用该方法。它提供了要求初始化的子类中所引起的一致性。
作为对象建立过程中附带影响,<somInit>是自动调用的(即由<somNew>调用)。如果不需要这种影响,你可以提供你自己的<somNew>的版本(在用户所写的元类中),而该<somNew>不引用<somInit>。
当覆盖该方法时,你应该在做你自己的初始化前,总要调用该方法的父类版本。
方法somUninit参数somSelf返回void描述(Un-initializeself)作为<SOMobject>的实例没有任意的实例数据,因而不做初始化,而且你不必调用该方法。它提供了在需要非初始化的子类中所引起的一致性。
使用该方法来清除任意必须清楚的东西,如动态分配的空间。然而该方法并不释放分配给对象实例的实存储器。可提供该方法是对<somFree>的补充,后者也释放与动态分配对象有关的存储器。通常你只需调用<somFree>,因为<somFree>总是会调用<somUninit>。然而在<somRenew>(见<somclass>的定义)用于建立对象实例的情况时,就不能调用<somFree>且你必须显示调用<somUninit>。
当覆盖该方法时,你总是应该在做你自己的非初始化之后,去调用该方法的父类版本。
方法somFree参数;somSelf返回void(没有)描述假设<Self>是由<SomNew>(或使用<SomNew>的另一个类方法)建立的话,则释放与<Self>有关的存储器。对于<Self>不曾做将来的引用。在释放存储器前将在<Self>上调用<SomUninit>。
该方法必须只能在由<SomNew>(见<SomClass>建立的对象上调用。
覆盖该方法是不必的(而用取代<SomUninit>)。
方法SomGetClassName参数SomSelf返回Zstring描述返回一个对该对象的类的名字的指针,作为一个空的结束串。因为它只是引用类对象的方法(<SomGetName>)来得到名字,所以就不必来覆盖该方法。
方法SomGetClass参数SomSelf返回SomClass*描述返回该对象的类对象。
方法SomGetSize参数SomSelf返回integer4
描述返回该实例的大小(以字节计)。
方法SomRespondsTo参数SomSelf,SomIdMid返回int描述如果是由该对象的类支持所指示的方法,则返回1(真),否则返回0(假)。
方法SomISA参数SomSelf,SOMClass*Aclasslbj返回int描述如果<Self>的类是<Aclassobj>的子孙类的话则返回1(真),否则返回0(假)。注意就该方法的目的而言,一个类对象可以认为出身于它自己。
方法SomIsInstanceOf参数SomSelf,SOMClass,*Aclsaaobj返回int描述如果<Self>是所指定的<Aclassobj>的实例,则返回1(真),否则为0(假)。
SOMObject方法支持动态的对象模型。对于真正的动态域而言,这些方法使它容易联编SOM对象协议边界。这些方法决定适宜的方法过程然而再以指定的自变量调用它。在该类所提供的这些方法的缺省的实现只是简单地用名字查寻该方法并调用它。然而,其它类会选择实现它们愿意查寻的任意格式。例如,一种可以提供使用方法判定的CLOS格式的这些方法的实现。对于可以这样做的域而言,它通常是快得多地直接引用它们的方法,而不是通过调度的方法。然而,所有方法通过调度方法都是可以达到的。SOM提供了包括了这些方法调用的外部过程的小的集合,因而调用者不必进行方法的判定。
说明这些方法可采用可变长度的自变量列表,但是像所有的这样方法在方法被实际引用前,对于可变长度的自变量列表而言,SOM对象规程边界需要将自变量列表的可变部份装配到标准的、专门平台的数据结构中去。这在运行时需要建造自变量列表的域中可能是非常有用的。因为它们能引用方法,除非能将建造的自变量放到正常的格式中以便调用。这是很有帮助的,因为这样一种操作在多数高级语言中通常是不可能的并且将必须使用专门平台的汇编语言例行程序。
注对不同返回值的种类要定义不同的方法。这就避免了存储器管理问题。如果需要附加的参数来传送返回值时,在某些域中就会引起这种存储器管理问题。除了下面所示的四种家族外,SOM不支持返回值。在一个家族中(如整数),SOM只支持最大的数。
方法SomDispatchV参数SomSelfSomIdmethodId,SomIddscriptor,…返回Void(没有)描述不返回值。
方法SomDispatchL参数SomSelf,SomIdmethodId,SomIddescriptor返回integer4描述在返回整数数据的正常方式下返回一个4字节的值。当然该四字节值可以是除了整数外的某种值。
方法SomDispatchA参数SomSelf,SomIdmethodId,SomIddescriptor返回Void*描述在返回这样数据的正常方式下返回一个数据结构地址。
方法SomDispatchD参数SomSelf,SomIdmethodId,SomIddescriptor返回float8
描述在返回浮点数据的正常方式下返回一个八字节的值。
支持开发的SOMObject方法为了支持程序的开发,特提供这一组方法。大多数开发的上下文将发现本组方法是容易利用的,在这种意义上,本组方法已有定义了。然而,某些上下文可能需要定做输入/输出设施。我们已经试图在真正可移植的方式下允许这样的定做,但是不是所有的上下文将能直接执行定做,因为它们需要传送函数的参数。我们选择这种途径,它使中性平台有很大灵活性,并且我们感到对于他/她的专门的开发环境而言,任意的开发支持的提供者将找到必须提供定做的理由。
所选择的途径取决于字符输出例行程序。外部变量<SOMOrtCharRoutine>指向该例行程序。SOM环境提供了实现该例行程序的环境,而该例行程序应该工作在多数的开发环境中(它写到标准的输出流中)。然而,开发的上下文可以对<SOMOutCharRoutine>分配一个新的值,因而重定义该输出过程。SOM对于进行这种分配不提供专门的支持。
方法SomPrintSelf参数SomSelf返回SOMAny*描述
使用<SOMOutCharRoutine>来写简短的关于这个对象标志信息的字符串。缺省的实现只是在存储器中给出对象的类名和它的地址。返回为<Self>。
方法SomDumpSelf参数SomSelf,intlevel返回Void(没有)描述使用<SOMOutCharRoutine>来写该对象的详细描述和它的现行状态。<level>指出了描述复合对象的嵌套级别,它必须大于或等于0。描述中的所有行前面要放<2*level>个空格。
该例行程序实际只是写那些基本上影响对象的数据,如类,并且使用<SomDu,mpSelfInt>来描述对象的现行状态。这种途径使要被建造的复合对象的描述是可读的。
通常覆盖此方法是不必的,如它被覆盖的话,通常它必须完全被替换。
方法SomDumpSelfInt参数SomSelf,intlevel返回Void描述使用<SOMOutCharRoutine>来写出该对象的现行状态。通常该方法将需要覆盖的。当要覆盖它时,通过调用该方法的父类的格式来开始,然后写出你的类的实例数据的描述,其结果在从它的根祖先类到它的专门类的所有对象实例的数据描述中。
SOMClass这是SOM元类。即这们类的实例是类的对象。当建立SOM环境时,就建立了外部名为<SOMClassClassData.ClassObject>的这个类的一个实例。这个类对象是唯一的,因为它是它自己的类对象。即,SOMClassClassData.ClassObject==-SomGetClass(SOMClassClassData.ClassObject)。这个类引入了用于建立SOM对象的新实例的SomNew和SomRenew方法。用于<SOMClassClassData.ClassObject>的SomNew产生一个新的类对象,然后可以对该类对象初始化使它成为特别的新类。SOMClass可以是就象任意的SOM类那样的子类。SOMClass的子类是新的元类,并且可以生成具有不同实现的由<SOMClassClassData.ClassObject>产生的那些类对象。
ftbSOMClass是从SOMObject传下来的。
SOMClass定义了下述的方法。
方法SOMNew参数SomSelf返回SOMAny*描述产生这个类的一个实例。当用到<SOMClassClsaaData.ClassObject>或任意其它元类对象时,该方法会产生一个新的类对象。当用到普通的类对象时,它会产生那个类的一个实例。
方法SomRenew参数SomSelf,SOMAny*obj描述产生这个类的一个实例,但是使用由<obj>指向的空间而不是为该对象分配新的空间。注由于不做测试所以要确保那个<obj>指和足够的空间。返回的是<obj>指向足够的空间。返回的是<obj>但它现在是指向一个有效的初始化的对象的指针。
方法SomInitClass参数SomSelf,ZstringClassName,SOMAny*parentClass,integer4instanceSize,intmaxStaticMethods,integer4majorVersion,integer4minorVersion返回Void描述初始化<self>。
<parentClass>是这个类的父(或父类),它可以是空的,在这种情况下,其缺省值为SOMObject(实际上是对于SOMObject的类对象的SOMObjectClassDlassData.ClassObject)如果指定了一个父类,则它必须已经被建立,因为需要一个指向它类对象的指针。
<instanceSize>应该是这个类刚好所需的空间,考虑父类(如有的话)的空间需求是不必的。
<maxStaticMethods>应该是由这个类定义的静态方法。考虑父类的方法(如有的话)是不必要的,即使如果在这个类中,它们被覆盖的话。
<majorVersion>指出了用于类定义的这个实现的主要版本号,并且<minorVersion>指出了最小版本号。
方法SomClassReady参数SomSelf返回Void描述当这个类的所有的静态初始化已经完成时,引用该方法。缺省的实现是用SOMClassMgr简单地注册新建造的类。元类可以覆盖此方法,以便以他们愿意的任意方式来扩展类建造的顺序。
方法SomGetName参数SomSelf返回Zstring描述返回该对象的类名作为一个以空(NOLL)结束的串。
方法SomGetParent参数SomSelf返回SOMClass*
描述如果父类存在的话,则返回自己的父类,否则返回一个空值(NULL)。
方法SomGetClassData参数SomSelf返回SomSelfDataSturcture*描述返回对向静态结构<ClassName>ClassData的指针。
方法SomSetClassData参数SomSelf,SomClasDataDturcture*cds返回Void描述对静态<className>ClassData结构设置类的指针。
方法SomDescendedFuom参数SomSelf,SOMClass*Aclassobj返回int描述如果<self>是<Aclassobj>的子孙类则返回1(真),否则为0(假)。
注就本方法的意图而言,类对象可以认为是它本身的子孙。
方法SomCheckVersion
参数SomSelf,integer4majorVersion,integer4minorVersion返回int描述如果该类的实现是与指定的较大的和较小的版本号兼容的话,则返回1(真),否则为0(假)。如果它具有相同的较大版本号和较小版本号,即等于或大于<minorVersion>,则实现是与指定的版本号兼容的。可以认为较大、较小的版本号对(0,0)是与任意版本匹配的。为了检验动态加载类定义是与使用的应用兼容性,在建立类对象之后通常立即调用此方法。
方法somFindMethod参数somSelf,somIdmethodId,somMethodProc**m返回int描述对于该类要找到与<methodId>有关的方法过程并将它置为<m>。当方法过程可以直接调用时,则返回1(真),而当方法过程是个调度函数时,则返回0(假)。
如果该类不支持所指定的方法则<m>置为NULL值(空),并且返回值是没有意义的。
返回调度函数并不保证一个类支持指定的方法,且高度可能会失败。
方法somFindMethodOK
参数somSelf,somIdmethodId,SomMethodProc**m返回int描述除了如果不支持该方法,则会引起错误且执行停止外,其它同<somFindMethod>。
方法somFindMethod参数somSelf,somIdmethodId返回SomMethodProc*描述发现所指示的方法,该方法一定是为该类定义的静态方法,且返回对它的方法过程的指针。如果对该类的该方法没有定义(没有作静态方法定义或根本上就没有定义)的话,则返回一个NULL(空)指针。
方法somFindSMethodOK参数somSelf,somIdmethodId返回somMethodProc*描述除了如果对该类没有定义该方法时会引起错误外,其它同<somFindSMethod>。
方法somSupportsMethod参数somSelf,somIdMid
返回int描述如果该类支持所指示的方法的话,则返回1(真),否则为0(假)。
方法somGetNumMethods参数somSelf返回int描述返回该类现行支持的方法数,包括继承的方法(静态和动态两种)。
方法somGetInstanceSize参数somSelf返回intger4描述返回<self>实例的整个大小。所有<self>的实例具有相同的大小。
方法somGetInstanceOffset参数somGetInstanceOffset返回integer4描述.;对于属于该类的实例数据而言,返回该对象体部份的偏移。
方法somGetInscePartSize参数somSelf
返回integer4描述返回对该类所需的实例数据以字节计的大小。这不包括对于该类的祖先或子孙类所需的实例数据空间。
方法somGetNumStaticMethods参数somSelf返回int描述返回该类所具有的静态方法数。这是在初始化它的方法表中由子类所用的。
方法somGetPClsMtab参数somSelf返回somMethodTab*描述返回对于该类的父类的方法表的指针。如果该类是根类(SOMBbject)的话,则返回NULL(空)。
方法somGetClassMtab参数somSelf返回somMethodTab*描述返回对该类方法表的指针。
方法somAddStaticMethod参数somSelf,somIdmethodId,somIdmethodDescriptor,somMethodProc*method,somMethodProc*redispatchStub,somMethodProc*applyStub返回somMoffset描述当增加/覆盖所指示的方法时,返回用于对该方法名的类数据结构中设置的偏移值。
<metbodDescriptor>是对于描述调用该方法顺序的串的somId,如同在SOMObject类定义中所定义的<somcGetNthMethodInfo>中所描述的那样。
<method>是该方法的实际方法过程。
<redispatchStub>是具有与<method>相同调用顺序的过程,它对该类的调度函数之一的方法进行重新调度。
<applyStub>是取标准变量的变元表数据结构的过程,且通过调用具有从该数据结构导出的变元的<method>,将它应用到它的目标对象中。它的调用顺序和调度在SOMObject中定义的方法的调用顺序相同。该存根用于支持某些类中使用的调度方法。在高度函数不需要这样功能的类中,该参数可能是空的。
方法somOverridesMethod参数somSelf,somIdmethodId,somMethodProc*method
返回Void描述当已知该类的父类已经支持该方法时,该方法可用来替换<somAddStaticMethod>或<somAddDynamicMethod>。该调用不需要方法描述符和其它方法实现的存根方法。
方法somGetMethodOffset参数somSelf,somIdmethodId返回intejer4描述假设这是静态方法。则返回在方法过程表中指定方法的偏移,否则如不是的话,则返回0。该值用于在该类数据结构中设置偏移值。当一个类用于定义现在它继承的方法时,使用该方法才是必要的。
方法somGetApplyStub参数somSelf,somIdmethodId返回somMethodProc*描述返回与指定方法有关的应用的存根。如果该类不支持本方法的话,则返回NULL(空)。应用的存根是用固定调用顺序调用的过程,即(SOMAmy*self,somIdmethodId,somIddescriptor,ap-listap),其中<ap>是具有要传送到该方法的实际变元表的各个变量的变元的数据结构。应用存根将该调用发送至它相关的方法然后返回由该方法产生的结果。
SOMClassMgrSOMClassMgr是从SOMObject传下来的。
SOMObject定义了下述的方法方法somFindClsInFile参数somSelf,somIdclassId,intmajorVersion,intminorVersion,Zstringfile返回SOMClass*描述对于指定的类返回类对象。该结果可能会引起动态加载。如果该类已存在的话,则<file>忽略不计,否则它用于定位并动态加载这个类。对于较大和较小的版本号,其值为0时则不进行版本检查。
方法somFindClass参数somSelf,somIdClsaaId,intmajorVersion,intminorVersion返回SOMClass*描述对于指定的类返回类对象。该结果可能会引起动态加载。使用somLocateClassFile来获得该类代码驻留的文件名,然后使用somFindClsInFile。
方法somClassFromId参数somSelf,SomIdClassId
返回SOMClass*描述找出该类的对象,如果它已经存在。则给与它Id,不用加载此类。如果该类对角不存在的话,返回NULL(空)。
方法somRegisterClsaa参数somSelf,SOMClass*clsaaObj返回Void描述让类管理程序知道已经安装了指定的类并且告诉它该类对象在哪儿。
方法somUnregisterClsaa参数somSelf,SOMClass*classObj返回int描述卸载该类文件并从SOM登记处除去该类。
方法somLocateClassFile参数somSelf,SomIdClassId,intmajorVersionm,intminorVersion返回Zstring描述这是由子类支持的实的实现。缺省的实现返回该类名作为文件名,子类可以使用版本号信息来支持派生的文件名。
方法somLoadClassFile参数somSelf,SomIdcladdId,intmajorVersion,intminorVersion,Zstringfile返回SOMClsaa*描述加载该类的代码并初始化该类对象。
方法somUnloadClassFile参数somSelf,SOMClass*clsaaObj返回int描述释放该类的代码并删除该类对象。
方法somGetInitFunction参数somSelf返回Zstrihg描述在类的代码文件中提供初始化函数名,缺省实现返回的是(*SOMClassInitFumcName)()。
方法somMergeInto参数somSelf,SOMObject*targetObj返回Void描述
将从接收程序得到的SOMClassM登记处信息合并到<targetObj>。要求<targetObj>是SOMClsaaMar的实例或它的一个子类。在这个操作完成时,<targetObj>应该能有作为接收程序的替换的功能。在该操作结束时,接收程序对象(它则处于新的未初始化状态)就被释放了。覆盖该方法的子类同样地传送该对象的子类部份并将该方法传送到它们的父类,作为最后的步骤。如果接收的对象是不同于总的变量SOMClassMgrObject所指向的实例的话,则重新分配SOMClassMgrObject去指向<targetObj>。
管理对象名本发明改进了过去对于一个类的每一个方法需要唯一的外部名的面向对象的技术,它是通过下述方法实现的在运行时通过与每个类的实现有关的专门过程来初始化类方法表和将一组方法偏移收集到外部命名的单个类数据结构中。这种改进减小了管理外部变量大表的复杂性,减少了建立唯一名字的困难(作为名字的基干(mangling)来引用,减少了存储器的需求并减少了生成执行模块的加载时间。
图3是遵照本发明的SOM类数据结构。标号310表示的是对表示在图2的248处的类对象数据结构的指针。标号320表示的是对图2的标号240处的方法过程表的偏移成对图2标号230处的对象的状态数据结构的偏移。类似地,标号330和340表示的是对方法过程表和它的状态数据结构的附加偏移。对于在该类中首次定义的方法或除了由类的祖先类之一定义外在类的释放次序部份中提到的方法,或者对于由这个类定义的公共实施例变量而言,而该类数据结构中有类似的入口,该类数据结构表示的是与这个类有关的偏移,如图上标号350处用省略号和“N+1”表示。由于第一个入口表示的是对类对象数据结构(图2的248)的指针,因而附加的入口是需要的。
在类数据结构中值的次序是由在该类的OIDL文件的释放次序部份中的对应的方法或公共实例变量名的次序决定的。在该类中定义的但是没有在释放次序部份提到的方法或公共数据成员次序是在释放次序部份提到的那些之后排序的,并且是以在类OIDL文件中出现的次序来排序的。
对象界面定义语言(OIDL)本发明重新定义了语言相关对象定义,因为它提供了对任意语言对象所支持的信息的中性集合。信息的中性集指的是在SOM中对象界面定义语言(OIDL)的定义。对于生成能用程序设计语言和提供SOM对象及它们的定义(指的是类)的联编文件而言,SOMOIDL提供了该基础。每个OIDL文件定义了对SOM对象的一个类的完整的界面。
OIDL文件对于不同的语言是以不同的格式出现的。不同的格式使类实现程序能指定附加的专门语言信息,该信息允许SOM编译程序提供对建造类的支持。这些格式中的每一个共享公共的核心语言,该语言指定了用户必须知道使用类的确切信息。SOM编译程序的设施之一是提取类定义的公共核心部份。于是,该类的实现程序可以维护类的专门语言的OIDL文件并且需要时可用SOM编译程序产生一个中性语言的核心定义。
本部份描述了具有支持C语言程序设计的扩充部份的OIDL。正如上面所指出的,通过SOM编译程序对OIDL文件进行编译并产生专门语言集或专门使用联编文件的集。
就C语言而言,SOM编译程序产生七个不同的文件。
·程序用到的类的公共标题文件。类的使用包括建立类的实例对象,调用实例对象的方法及再细分该类以产生新的类。
·专有的标题文件,它提供了使用对该类可能具有的任意专有方法的联编。
·实现的标题文件,它提供了宏和其它支持该类实现的材料。
·实现的模型,它提供了该类的实现的轮廓,然后类的提供者可对它进行编辑。
·中性语言核心定义。
·专有的中性语言核心文件,它具有该类接口的专有部份。
·OS/2的.DEF文件,它可以用来装配OS/2DLL格式的类。
OIDL文件可能具有下述几节·蕴含节;
·类节;
·释放次序节;
·元类节;
·父类节;
·通过节;
·数据节和·方法节。
包括节该节是需要的,它具有一个蕴含语句,它指示OIDL预处理程序对于这个类的父类、类的元类而言,如该类只指定其中一个的话,则告诉编译程序哪儿去发现该类的界面定义,而对于该类覆盖了一个或更多的它的专有方法而言的任意祖先类来说,OIDL预处理程序告诉编译程序哪儿去发现专有界面文件。
类节该节是需要的,它介绍了给它名字的类、属性和大体上可选的该类的描述。
释放次序节该节是可选的,它具有释放次序语句,它迫使编译程度去建立具有按指定次序按排项的相当关键的数据结构。这使类接口和实现得以发展,而不需要使用这个类的程序去重新编译。
释放次序用于所有的方法名和公共数据项。如果某个方法或公共数据项的释放次序没有指定的话,它将用缺省的基于OIDL文件中它的出现的情况的专门实现次序。新的公共数据项或方法的引入会使其它公共数据项或方法的缺省排序发生变化,因而使用该类的程序将需要重新编译。
元类节该节是可选的,它指定了该类的元类,给定它的名字及任选的对于该元类的理由的描述或在这个类的界面中关于它的作用的其它的说明。如果指定元类的话,则它的定义必须包括在包括节中。如果没有指定元类的话,则这个类的父类的元类将被使用。类的元类也可以隐含定义,它是通过数据节的类的属性和方法节的类的属性组合使用来实现的。如果使用这些属性中的任一个,则元类节必须被旁路掉。在这种情况下,隐含的元类将是父类的元类的子类。
父类节该节是需要的,它通过指示其名字或任选的在这个类的界面中对其父类作用的描述来指定该类的父类。
通过节该节是可有可无的,它提供了编译程序进入到不同的联编文件中的代码块。编译程序对通过的信息内容是忽略的,即使处理通过行中所有的说明时也不作修改。
数据节该节是可有可无的,它列出了这个类的实例的变量。该节通过只是以类界面(.CSC文件)的语言专门版本表示的。然而,如果该类具有公共实例变量的话,它必须以类界面定义的公共格式来表示。美国国家标准化学会(ANSI)C语法用来描述这些变量。
方法节该节是可有可无的,它列出了该类所支持的方法。ANSIC函数原型语法用于定义对每种方法调用的顺序。
SOM编译程序SOM编译程序将SOM类的OIDL源定义翻译成适于一个特别的程序设计语言的联编集。对于C程序设计语言,由OS/2.0工具集(ToolKit)支持的编译程序产生一个联编的完整集。
编译程序在两个阶段-予编译阶段和发行阶段。在第一阶段,予编译程序读并且分析用户支持的类定义,产生中间输出文件,该文件包含二进制类信息、说明和通过的行。在第二阶段,一个或更多的发生程序达到产生适当的语言联编文件。对于SOM前编译程度阶段,两个附加的程序用作预处理程序。由SOM编译程序指示所有这些程序的排序和执行。C编译程序接着编译发生程序的输出加上用户支持的该类方法的逻辑,再由OS/2的链接程序加以链接以建立可加载模块。可加载模块可以装配到自含文件中或放到DLL中,因而许多程序可以用这个类。
参考图4,在端400处控制开始并直接进行到功能块404,其中SOM的语言中性对象界面定义(OIDL)402输入到SOMOIDL编译程序404中。SOMOIDL编译程序分析OIDL的对象定义,再进到中间格式406以简化代码生成过程,再作为输入进到目标语言的发行程序410。语言发行程序410生成语言联编414,它包括了图3所描述的类数据结构。控制再进到功能块420所示的语言编译程度,它从语言应用416和S)M联编412处接收附加的输入。语言编译程度可能是C、FORTRAN、COBOL或取决于用户喜欢的其它编译程序。语言编译程序的输出是对象文件442,它可以与SOM运行时的库链接编辑,以用于以后的执行操作。
图5描述了基于本发明的使用SOM对象的应用的链接、加载和执行的流程图,处理在端口500处开始,并立即进到对图4标号422处建立的SOM对象510和SOM运行时间库520进行动态链接和加载的功能块530。然后,在功能块540处应用开始,它调用建立必要的类和对象,这一功能如功能块550所表示其详细可见图6、7、8、9和10。最后,如功能块560所示,执行该应用并且控制在端口块570处结束。
关于面向对象程序的版本的独立性本发明的这方面通常是和下述两方面的改进有关的,其一是在面向对象的应用方面,其二则是特指解决从对象定义库的独立发展和使用它们的计算机应用所提出的问题这一方面。
版本独立处理隔离了计算机应用的可执行的二进制格式,该应用使用在对象定义的实现或规范中的一定变化的对象定义库(也叫做对象类库),其中在库的生命周期期间,对象定义会自然提出。具体地说,对于对象定义而言,不需要危及它的使用就可以通过计算机应用(该应用每次执行时,动态加载该对象定义)的不修改可执行的二进制格式来实现下述变化。
1.对对象定义增加新的方法;
2.对方法而言,将定义点从子类移到它的父类。
3.加、删除或修改与对象定义有关的专有实例数据;且4.将新的类定义插入到类的层次中。
通过如下所述的使用几咱技术的处理器的存储器中的算法操作来完成这个过程。将方法和实例偏移从应用二进制映象中除去。在静态对象模型中,如同在C++定义的对象模型,对每个特别的方法名可以用将偏移(整数)放到方法过程表的办法来选择方法过程。该偏移取决于定义方法的类的方法数和次序,也取决于由它祖先定义的方法数。
该途径具有方法判定的非常快的格式的益处。然而,在以前的技术中,对象模型已经放到使用特别对象类的应用二进制映象中的这些偏移中,其结果是只要偏移需要修改,应用就需要重新编译。
在SOM中,对于每个类,与方法有关的偏移收集到单个存储器数据结构中,该结构叫做类数据结构,详细见图3的讨论。给这个数据结构一个外部名且其内容涉及到应用中。当类对象初始化时,每个类数据结构初始化成具有合适的偏移值。详细见图10。于是每次执行应用时,根据应用所用的类的现行定义来重新计算所有的偏移值。
注在应用的二进制映象中任意对存储在类数据结构中的值的访问都具有偏移。然而,这些偏移在前述的整个四种修改中可能保持为常数。这是因为对于在特别的类中定义的方法而言,类数据结构只含有偏移,而对于由类继承的方法的偏移而言,则不然。于是,加到类的新方法可以具有它们加到类数据结构末端的偏移,而不会打乱在类中已定义的方法的偏移值的位置。
SOM对象界面定义语言(OIDL)具有在上面标题为“SOM对象模型”节中讨论的释放次序节。OIDL的释放次序节使类实现程序来确保对于在类中已定义的方法而言将新方法偏移值加到该方法偏移值之后。如果象图3突出部分所示那样,把类定义的方法之一移到父类的话在OIDL文件中释放次序节也会使在类数据结构中保持一个项。然后,简单的赋值语句用父偏移值来初始化该项。OIDL编译程序将该赋值语句加到逻辑初始化类数据结构中,如图10所描述的。
伴随着公共实例数据,类似的问题产生了存取包含在一个应用对象的状态数据结构中的公共实例变量的应用必须这样做,即通过偏移进入到对象的状态数据结构中。在以前的技术中,这个偏移是在应用的二进制映象中。如果应用这种技术,则由于一个或几个对象的视先类的实例数据需求的大小变化时或由于对象的自己的实例数据层次变化时引起的任意时候偏移变化时,必须重新生成该应用的二进制映象。
在SOM中,这个问题的解决是通过将每个公共数据变量的偏移放在类数据结构中加以解决的。详述见图3和随后的讨论。当类对象初始化时,每个类数据结构也初始化了,并使它具有合适的偏移值,详述如图7和13所示。于是,每当应用执行时,根据应用所用的类的现行定义去重新计算全部的偏移值。
从应用的二进制映象中除去对象状态数据结构。
当对象的新实例建立时,必须分配计算机存储器正确的容量以保持对象的状态数据结构。在以前的技术中,存储器的这个块的大小是在应用的二进制映象中。如果用这个技术,则任意时候对象的状态数据结构的大小变化时,必须重新生成(通过重新编译)应用的二进制映象。在SOM中,通过调用对象的类对象来获得该值的,因而不必包含在应用的二进制映象中。
上面描述的技术使以前强调的四种变化的每一咱会产生关于由应用使用的类定义而不需要重新生成应用的二进制映象。
图6是描述按照本发明的新SOM类的建立的流程图。控制在端口600处开始,它立即走到判断框610处去测试得到正确的版本号,在610处执行检查以便验证版本号的正确性。如果检测到不正确的版本号,则在输出框612处显示信息并在端口框614处结束控制。如果检测到正确的版本号,则上判断框620处执行另一测试以便决定SOM类是否存在。如果SOM类存在,则处理在端口框622处返回。
如果SOM类在判断框620处不存在的话,则在判断框630处再测试以决定SOM运行时的环境是否有效?如它无效的话,则在功能块632处引用SOM运行时环境。不管SOM环境开始存在与否,控制流程然后再运行到判断框640处以检查判断框640处SOM环境中有否错误。如检测到错误,则在输出框642处给出适当的信息。如检测不到错误,则控制传送到准备缺省的元类的功能框650处,下一步,在细节如图7所示的功能框652处建造一个类。最后,处理在端口框660处返回。
图7为根据本发明描述详细建造新的SOM类的流程图。控制在端口700处开始并立即运行到建立通用类对象的功能块710处,详述见图8。下一步在功能块720处将新的通用类初始化到缺省值,详述见图9。然后,在功能块730处,对该特别的新类,初始化实例数据偏移。控制再运行到功能块740处,在该处通过分配表示该新类的每个静态方法值来初妈哗新类的类数据结构(图3),详述如图10所示。
在功能框750,760和770处,设置父类,初始化类数据及注册该类。这些步骤包括在图2、10和13讨论中详述的更新此新类数据结构。最后,控制在端口780处返回。
图8为描述根据本发明详细建造新SOM通用类对象的流程图。控制在端口800处开始,并立即进到为对象分配存储器的功能块810处,然后在判断框820处进行测试以判断存储器是否已分配。如检测到错误,则在输出框830处显示适当的错误信息,旦处理在端口框840处结束。如检测不到错误,则在功能框850处设置对象的缺省值,然后控制在端口框860处返回。
图9为描述根据本发明详述初始化新SOM类对象的流程图。控制在端口900处开始并立即进到判断框910且进行测试以检测新SOM类对象的父类是否存在。如父类存在,则在功能框912处初始化父类。一当初始化父类,则在功能框920处分配该类名的存储器。下一步,在判断框930处再执行测试以检测新SOM类对象的父类是否存在。
在父类不存在,则将初始变量置为0,如功能框932处所示,然后控制传送到功能框970处。如父类存在的话,则根据功能框940、950和960处父类的值来更新初始变量。然后,在功能框970处,设置该类的版本号且在判断框980处执行错误处理。如检测到错误,则在输出框982处显示适当信息且在端口框984处结束处理。如检测不到错误,则控制在端口框990处返回。
图10为描述根据本发明详述的S初始化具有偏移值的SOM类数据结构的流程图。控制在端口框1000处开始且立即进到功能框1010处,在该处取得下一静态方法的循环开始。在功能框1020处,以SOM运行时环境注册新方法的标识。然后,在判断框1030处执行测试以判断该方法是否已经在父类中注册。如该方法已经注册,则在功能框1032处覆盖该方法偏移然后控制再传送到判断框1070处。
如果该方法还没有以任意父类来注册的话,则在判断框1040处执行测试以判断该方法是否已经在当前类中定义。如该方法已经定义,在功能框1042处使用存在的偏移,然后将控制传送到判断框1070处。如果该方法还没有定义,则在功能框1050和1060处分配存储器及初始化一些值。在功能框1060处通过将继承的静态方法数加到至今为止由该类已处理的继承的静态方法数的方法来计算偏移。在判断框1070处执行错误处理,且如果检测到错误,则在输出框1072处显示适当的信息且处理在端口框1074处结束,在错误处理完成之后,在判断框1080处执行另一测试以判断任意附加的方法是否需要处理。如有附加的方法,则控制传送到循环的下一选代的功能块1010处。否则,控制进行到控制返回处的端口1090处。
父类影子本发明的本节详细描述了提供关于在对象程序设计中作为父类影子的替换父类的动态插入逻辑。该处理使运行时链接到一个特别类的父类的静态编译定义能在执行期间动态变化。将新的父类插入到静态编译类的层次中的能力对维护和增强已经以二进制格式出现之后的存在的代码提供更多的灵活性。它对定做代码也提供了新的自由度而不需存取源材料,因为该结果不需重编译就可达到。
以前的技术系统具有与静态链接派生的类和它们的父类相关的继承限制。这些限制包括计算派生的对象状态数据结构的大小,初始化派生方法过程表和不能从派生的类的方法里提供存取父类的方法(叫做父类判定)。
SOM对象模型通过在运行时经由父类对象得到的所有父类信息来除去这些静态的基准。于是,当派生的类的实现需要下述信息时父类的状态数据结构的大小,父类的方法过程的地址或存取父类的方法过程表(以支持父类判定),可将适当的调用放到从父类对象得到的信息中。图7、8、9和10给出了为获得该信息的详细处理。
对于每个SOM过程而言,SOM引入了类管理程序。类管理程序的责任是管理类的登记处。无论何时建立子类对象时,由SOM编译程序生成的类建造代码与类管理程序一起工作,以建立类与它的父类之间的关系。SOM类管理程序是一个象任意其它SOM类一样可能是子类的这样的类的实例。
派生类通过调用SOM类管理程序对象来建立对它们的父类对象的连接。想要用一个替换类实现来替换原始类实现的应用设计者可以沿着下面步骤来进行1.子类SOMClassMgr提供了用于从类名来决定类对象的应用专门规则的新的集合(即改变SOMClassFromId,somFindClass和somFindClsInFile的实现)。
实现此事的简单和有用的方法是在已存在的类名下将方法加到注册影子类对象中,然后,将影子类对象返回到随后调用的调用应用中。而该随后调用是对指定影子名的somClassFromId,somFindClass,或somFindClsInFile的调用。
2.在建立任意将具有影子父类对象的派生类对象前,建立新类管理程序类的实例(如上面第一步所述),从已存在的SomClassMgr实例对其初始化(通过somMergeInto方法),然后用在SOM运行时覆盖已存在的somClassMgr实例的地址的办法,用新类管理程序实例来替换已存在的soMClassMgr实例。
3.在建立要求具有影子父类对象的任何派生类对象前,仍使用与指定应用有关的类管理程序对象的应用设施来寄存影子类对象。
在上述三个步骤完成之后,就可以建立派生类对象。它们将被链接到适当的父影子类对象。由于使用初始化类对象的专门逻辑,这是可以工作的并且将其链接到它的父类对象中,如图11所描述的。该逻辑由两个基本步骤组成1.首先,为了确保静态已知父类对象已经建立,要实现一个调用。这是用于两个重要的目的(a)它建立了对静态已知父类定义的二进制映象的静态基准,于是保证了将该父类实现链接到应用的二进制映象中。
(b)它保证在下一步发生前,SOM类管理程序对象至少是静态已知的父类对象已经和SOM类管理程序对象一起被注册。
如果静态已知父类对象已经建立的话(可以说用上面讨论的应用下述如影子的步骤来建立),则此时可忽略第二个试图。
2)其次,为了让SOM类管理程序对象根据派生类的父类名去检索适当的类对象的地址要实现一调用。如果父类已经有其影子的话,则该调用返回影子类的对象。
技术和上述机构的结合能有效地将派生类的二进制映象与类对象的确切类的相关性相隔离,而该生类用于从该类对象中提取父类数据。
当在子类与它的父类之间插入一个新类时,必须注意到两个限制。首先,插入必须在该子类的任意实例已经建立前完成。其次,该插入的类也必须是该原始父类的直接子类。因为当在运行时建立类之间的关系时,SOM类管理程序可以作为一个媒介,因而即使是一个静态链接的类也可以是以这种方式的一个影子。
图11为描述根据本发明的静态定义类层次的父类影子细节的流程图。控制在端口框1100处开始,并立即进到建立静态定义父类对象的功能框1110处。下一步,在功能框1120处建立影子父类并且来覆盖静态定义父类。然后,如功能框1130所示,建立其子类且该子类询问SOM类管理程序以确定它现行的父类而不是静态定义的。控制在端口框1140处返回。
重调度方法存根面向对象的程序设计的主要方面是方法判定。该处理选择了给定对象的特别方法,方法的标识及传送至方法启用的变量。在许多对象模型中,如在C++中使用的,方法判定是根据对程序的源代码的分析,包括了决定在过程入口点的对象专门表中的偏移。这种类型的判定指的是在对象模型中作为静态类型来考虑的。在其它对象模型中,如在Smalltalk中所用的,使用了更动态的模型,它包括了在运行时使用该对象名来决定专门的方法。在对象模型中,这种类型指的是动态类型。
本发明包括了叫做重调度存根的程度设计机构以改善静态和动态模型间的差异。重调度存根是具有入口点的小过程,它可以放到过程入口点的表中。该过程入口点表是用在静态对象模型中,作为替换期望的实际方法入口点。根据动态对象模型的需求会自动生成重调度存根,该重调度存根把静态对象模型中生成的调用转化为动态对象模型中所必须的格式,并提供处理中遗失的任意信息。于是,如果从由动态对象模型提供的静态对象模型中存取一个对象的话,它可以通过每个指示一个特别的重调度存根的入口点表来表示成静态对象模型。
图12为描述根据本发明的重调度方法的流程图。标号1200是特别对象的状态数据结构。在标号1210处的第一个全字具有对象的方法过程表(标号1240)的地址。表示在标号1230处的状态数据结构的余下部份具有关于对象的附加信息。表示在标号1240处的方法过程表具有特别对象的各种方法的地址。所有与该对象属于相同类的对象也具有指向这个方法过程表(标号1240所示)的地址。任意由该对象继承的方法将具有在存储器中与它继承的祖先类的方法过程表(在标号1240处表示的)中出现我的相同偏移处的方法过程地址。
在该图中,标号1250具有对重调度存根1270的指针。重调度存根是作为对客户程序的方法的指令序列。然而,这些指令只是将该方法调用转换成对对象的适当的高度功能的调用,如标号1260处所示。标号1260处的地址是对对象的调度功能1280的指针。所有SOM对象均具有调度功能。该调度功能1280根据由重调度存根传送的参数实现选择特别方法的一种算法。这些参数包括方法的标识符,描述传送给区分方法的变量集的串和具有变量集的数据结构。
偏移值图13描述对于单个公共实例变量的SOM类数据结构中的偏移值的初始化细节的流程图。该逻辑序列对于每个在特别的类中定义的公共实例变量而言是重复的(见前面OIDL数据节的讨论)。控制在端口框1300处开始,并立即进到功能框1310处,在该框中实例变量的偏移的计算是通过将这个类的对象状态数据中的实例变量的偏移加到在对象状态数据结构(表示在图2的标号230处)中的这个类的对象状态数据的开始偏移来实现的。
通过将这个类的祖先类的对象状态数据的每个大小加起来的办法来决定类的对象状态数据的开始处。当计算出的偏移存储到类数据结构的位置中时,控制就传送到功能框1320处,因为由在OIDL文件释放次序节(见上面OIDL释放次序节和上面的图3)中的公共实例变量名的位置来决定类数据结构的位置。然后控制再传送到端口框1330,则该过程完成了。
重调度存根图14是描述当使用重调度存根将静态方法调用转换为动态方法调用时所发生的控制流程细节的流程图。控制在端口框1400处开始,且立即进到功能框1410处,在该框中以正常的静态方法判定方式来决定重调度存根地址,它是通过取得存放在对象方法过程表的一个偏移中的地址来实现的。而该偏移是放在适当的类数据结构由类定义后决定的位置中的。
控制再传送给功能框1420处,在该框处调用重调度存根,就象它是真正的静态方法过程一样。功能框1430描述了重调度存根是如何调用该对象的调度方法的(使用如前面所述的正常方法判定)。当对象的调度方法需要时,重调度存根将方法的标识符和描述符加到该调用中。当由SOMOIDK编译程度生成重调度功能定义时,这些值将加到重调度功能定义中。(注详见上面的SOMObject类的定义,所有的类必须支持调度方法),该对象的调度方法过程决定了使用对该对象的类的专门算法的哪一个实际方法过程应该被调用,如功能框1440所示。
SOM提供了这样一种算法的默认的实现方法,该算法是在包含该对象的类对象表中查找该方法标识符,以决定方法过程的地址。其它对象模型会使用其它算法。控制再传送到调用由框1440决定的方法过程的功能框1450。如果在端口框1460处任意的过程返回到重调度存根的原始调用者的话,那时该方法过程返回它的返回值。重调度存根使原始的静态方法调用可以转换成任意的动态方法调用之一,而不需要修改操纵该对象的应用程序。
方法过程表初始化图15是描述正确初始化类的方法过程表的详细控制流程的流程图,这个类在使用该类的应用执行期间可能会改变方法过程对方法的关联。控制在端口框1500处开始,并立即进到为方法过程表分配空间的功能框1510处。为了含有该类的对象的地址入口和按照图7由该类继承或定义的每一种方法,需要分配足够的空间。控制再传送到重调度存根替换方法过程表中的每个方法入口的功能框1520处。通过从该类的父类中请求重调度存根来决定继承的重调度存根。由SOM编译程序生成类的重调度存根并在注册每个该类的静态方法调用中支持该类的初始化过程。控制再传递到功能框1530中,在该框中由该类的调度功能的实际地址来替换该类的调度功能的方法过程表入口(在调度功能槽中具有重调度存根地址是绝对不对的,因为这会使结果处于无限的循环中)。最后控制传送到端口框1540处且处理完成。
尽管本发明是根据专门系统环境中的择优的具体设施加以描述的,然而在技术上有经验的人们会认识到在附加的专利权利精神和范围内的其它不同的硬件和软件环境中,本发明是可以实际操作并加以修改的。
权利要求
1.用于组织一组带有方法名的类的装置,该方法名代表的方法由计算机存储器中功能实现,其特征是(a)用于初始化每个类的方法过程表的装置;(b)用于静态定义每个类的全部功能的装置;(c)用于将每个类的偏移变量集中到数据结构的装置;且(d)用于在计算机存储器中对每个类的数据结构形象化的装置。
2.如权利要求1所述的装置,其特征在于(a)包括了用于在磁盘或其它存储介质上存储方法过程表的装置。
3.如权利要求1所述的装置,其特征是用于在运行时初始化(c)的偏移的装置。
4.如权利要求1所述的装置,其特征是用于覆盖(a)的方法的装置。
5.如权利要求1所述的装置,其特征是用于唯一区分(a)的方法而不需要改变方法名的装置。
6.用于组织具有由计算机存储器中功能实现的方法的方法名表示的类的集合的方法,其特点在下述步骤中(a)对于每个类对方法过程表进行初始化;(b)对于每个类静态定义所有功能;(c)对于每个类将偏移量集中到数据结构中;且(d)在计算机存储器中对于每个类将数据结构形象化。
7.如权利要求6所述的方法,其特征是(a)包括了在磁盘或其它存储介质上存储方法过程表的步骤。
8.如权利要求6所述的方法,其特征是运行时初始化(c)的偏移的步骤。
9.如权利要求6所述的方法,其特征是覆盖(a)的方法的步骤。
10.如权利要求6所述的方法,其特征是唯一区分(a)的方法而不需改变方法名的步骤。
全文摘要
通过集中所有名的表示和额外地支持在单数据结构中的信息的办法来有效地管理类方法名的方法、系统和程序。通过使用两个机构的处理器存储器中的算法操作来完成管理,先由类专门过程来初始化类方法过程表,这使应用能存取方法而不需对方法名形象化。由类对象保持由专门过程提供的信息且无论何时需要该信息,通过类方法便可使用它的。对于方法的任意附加支持信息,特别是,对于每个方法的方法过程表中的偏移是记录在单个外部命名的数据结构中的。
文档编号G06F9/44GK1073540SQ9211349
公开日1993年6月23日 申请日期1992年11月23日 优先权日1991年12月12日
发明者迈克·H·克讷, 安卓·R·马丁, 兰瑞·K·瑞泊 申请人:国际商业机器公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1