《第九章 类与对象.doc》由会员分享,可在线阅读,更多相关《第九章 类与对象.doc(8页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第九章 类与对象类与对象是面向对象编程的根本概念,类:对具有相同属性和行为的一类事物的抽象描述,共同属性被描述为类中的数据成员,共同行为被描述为成员函数。类所描述的事物具有共同的属性和行为(操作),但每一个具体事物(又称为个体,实例或对象)都具有属于自己的属性值和行为特征。9.1 什么是C+对象模型有两个概念可以解释C+对象模型:1.语言中直接支持面向对象程序设计的部分2.对于各种支持的底层实现机制本书讲解的是编译器的构造技术,因此将忽略语言层面的支持,而集中讲解各种底层实现机制。在C语言中,数据和“处理数据的操作(函数)”是分开来声明的,也就是说语言本身并没有支持“数据和函数”之间的关联性,
2、我们把这种程序方法称为程序性的( procedural ),由一组分布在以各个功能为导向的函数中的算法所驱动,它们处理的是共同的外部数据。例如我们声明一个struct Poind3d,声明方式将像下面这样:tvpedef struct pointedfloat x;float y;float z;Point3d;class point3dpublic:point3d(float x = 0.0, float y = 0.0, float z = 0.0): _x( x ), _y( y ), _z( z )float x() return _x;float y() return _y;floa
3、t z() return _z;void x(float xval) _x = xval;/ .etc.private:float _x;float _y;float _z;inline ostream& operator(ostream &os,const Point3d &pt)return os(pt.x(),pt.y(),pt.z()x , pd-y , pd-z);而在C+中,我们就可以用独立的“抽象数据类型 abstract data type ,ADT ”来实现,定义一个 Point3d类。在C+中,有两种类成员变量类型:static和nonstatic,以及三种类成员函数类型:
4、 static, nonstatic和virtual。已知下面这个class Point声明:class Pointpublic:Point(float xval);virtual point();float x() const;static int PointCount();protected:virtual ostream& print(ostream & os) const;float _x;static int _point_count;这个class Point在机器中将会被怎么样表现呢,该如何被存储呢?也就是说我们如何模塑(modeling )出各种data members和fun
5、ction members。9.1.1 简单对象模型(Simple object Model)为了尽量减低c+编译器的设计复杂度,我们可以使用简单对象模型。但是我们牺牲的则是空间和执行期的效率。在这个简单模型中,一个object 是一系列的slots,每一个slot指向一个members,每一个member按其声明次序,各被指定一个slot。每一个data rnember或function member 都有自己的slot。图9.1说明了 这种简单的对象模型。图9.1 简单对象模型在这个简单模型中member本身并不放在object之中,只有“指向 member的指针才放在object内。这么
6、做可以避免“members有不同的类型,因而需要不同的存储空间”所招致的问题。object中的members是以slot的索引值来寻址,例如本例之中_x的索引值是6,_point_count的索引值是7。一个object的大小很容易计算出来:“指针大小,乘以class中所声明的members数目”。9.1.2 表格驱动对象模型(A Table-driven Object Model ) 为了对所有classes的所有objects都有一致的表达方式,另一种对象模型是把所有与members相关的信息抽出来,放在一个data member table和一个member function table
7、之中,class abject本身则内含指向这两个表格的指针。member function table是一系列的slots,每一个slot指出一个member function。data member table则直接含有data本身,如图9.2所示。图9.2表格驱动对象模型9.1.3 C+对象模型The C+ Object ModelC+语言中的对象模型并没有采用上面的两种方式,却吸收了两者的优点。 Straustrup当初设计当前亦仍占有优势的C+对象模型是从简单对象模型派生而来的,并对内存空间和存取时间做了优化。在此模型中,nonstatic data members被配置于每一个cl
8、ass object之中, static data members 则被存放在所有的class object之外。Static和nonstatic function members也被放在所有的class object之外。virtual functions则以下面两个步骤提供支持:1每一个class产生出一堆指向virtual functions的指针,放在表格之中。这个表格被称为virtual table (vtbl)。2. 没一个class object被添加了一个指针,指向相关的virtual table,通常这个指针被称为vptr, vptr的设定setting和重置(resetti
9、ng)都有每一个class的constructor. destructor和copy assignment运算符自动完成。每一个class所关联的type_info object(用以支持runtime type identificator,RTTI)也经由virtual table被指出来,通常是放在表格的第一个slot处。图9.3 C+对象模型 图9.3说明C+对象模型如何应用干前面所说的Point class身上。这个模型的主要优点在于它的空间和存取时间的效率,主要缺点则是,如果应用程序代码本身未曾改变,但是所用到的class objects的nonstatic data members
10、有所修改(可能是增加、移除或更改),那么那些应用程序代码同样需要重新编译。关于这点,前述的双表格模型就提供了较大的弹性,因为它多提供了一层间接性,不过它也因此付出空间和执行效率两方面的代价就是了。9.2 一种简单的面向对象语言的编译器的设计与实现为了举例说明面向对象语言的编译技术,我们将扩充简单的C语言的文法规则,支持面向对象语言的成分。9.2.1对文法的扩充为了支持类与对象,对原文法扩充如下:decl var-decl | fun-decl | cls-declcls-declaration class ID var-declaration | fun-declaration / 类的声明v
11、arID | ID.ID | this.ID/变量和类的成员变量访问var = new ID ( args )/对象创建call ID( args )| ID.ID (args)/函数调用和类的成员函数访问9.2.2 词法分析为了支持类,在词法分析程序中添加与类相关的关键字。这些关键字包括:class publicprotectedprivatenewdelete9.2.3 语法分析与抽象语法树按照修改的文法,进行语法分析。在语法树中添加ClassDecl节点类型,表示一个类的定义。比如对如下的类声明,同学们可以根据以前所学到的知识画出它的语法树。class Point int x; int
12、y; int z; void Init(int a, int b , int c) x = a;y = b;z = c; 9.2.4 符号表设计与构造在符号表设计中,增加类表,用于记录类的信息。类表设计如下:名称类型说明class_namestring类名membervar_sizeintmembervar_listHashtable列出所有的成员变量memberfun_listHashtable列出所有的成员函数构造过程:在语义分析的时候,遇到ClassDecl节点,就调用processClass 对类声明进行处理。类声明中有两类元素,一个是成员变量,一个是成员函数。 对这两类元素分别处理,
13、过程与处理全局变量和全局函数基本相同, 在分别将分析结果加到成员变量列表和成员函数列表中。最后将整个类的信息返回, 在被加到类表中。9.2.5 代码生成1、对象的创建在虚拟机机上有new 指令,创建对象非常直接。比如如下的语句P = new Point();生成代码NEW p引用地址,Point2、对象成员变量的访问根据对象模型,根据对象引用查询类的成员变量表,获得成员变量的相对偏移地址,再求得在堆上的相应地址,访问变量。在外部访问成员变量的情况,需要根据对象的this指针找到对象的地址。例如程序:class pointpublic:int x,y,z;point p;p = new poin
14、t;p.x = p.y + p.z;对于语句p.x = p.y + p.z ;生成如下代码(假设p的地址为bp+3)Mov ax , bp+3_2Mov bx, axMov ax, bp+3_1Add ax, bxMov bp+3_0, ax对于在成员函数内部访问成员变量的情况,可以直接根据函数的this指针找到变量地址。例如如下代码:class Point int a; f1(int x) a = x; 转化为f1(Point this, int x) this.a = x; 生成代码如下: (变量a的地址可以在bp-1处取得) Mov ax , 1 Mov bp-1_0 , ax3、对象成
15、员函数的访问通过成员函数设置this指针来实现,成员函数的this指针指向调用该函数的对象引用。调用成员函数,如果是外部调用,需要根据对象引用获取this指针,查找符号表,找到函数地址,执行函数调用。例如下面的程序段:Point p;p = new Point();p.Init();语句p.Init()将被编译器自动转换为:Point_Init(p);生成代码如下: ;函数参数入栈Mov ax , bp+3 ;/取得p对象的地址Push ax ;对象地址入栈Call Point_Init对于内部调用,则直接根据调用函数的this指针查找符号表即可。例如:class Point f1() f2(
16、); f2(); 函数f1()被编译器自动转化为Point_f1(Point this) Point_f2(this); 生成代码如下: Mov ax, bp-1;取得this指针 Push ax Call Point_f29.2.6 运行情况例如程序段:p = new Point();p.Init(0, 0);p.x=3;p.y=5;生成的目标代码如下:New bp+3,PointMov ax, 0Push axMov ax, 0Push axMov ax, bp+3Push axCall Point_InitSub sp, 3Mov ax, 3Mov bp+3_0, axMov ax, 5Mov bp+3_1, ax