




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、在面向对象设计范型中,使用了数据抽象的概念,即数据总是与施加它们的操作绑定在一起的。这就要求语言具有符合数据抽象的系统预定义数据类型,特别需要提供能设计符合数据抽象用户自定义类型的构造数据类型(例如 C+ 和 Java 语言中的类类型class)。程序中的数据和操作都是由按数据抽象封装起来的对象提供的。3.1.1 C+ 的类类型定义在 C+ 中,用户可以使用类类型关键字 class 定义自己的抽象数据类型。这种定义方法和形式与使用结构体类型关键字 struct 定义数据结构类型十分相似。例如,可以用 struct 定义描述学生基本信息的数据结构类型 Student,并可以使用该数据结构类型定义
2、结构变量stud1,stud2:struct Student int num;char name20; char sex;Student stud1, stud2;同样,可以用 class 定义描述学生基本信息和基本操作的数据类型Student,并可以使用该数据类型定义对象 stud1,stud2:class Student int num;char name20; char sex;public:void display() cout “num: ” num endl; cout “name: ” name endl; cout “sex: ” sex endl;Student stud1,
3、 stud2;比较两种用户自定义类型,它们的共同之处表现在: 类型定义首行具有相同的格式,由关键字(struct 或class)与自定义类名组成。例如:“struct Student”和“class Student”。 类型定义体都使用左花括号“”表示开始,使用右花括号“”表示结束,并用分号“;”表示整个自定义类型定义工作完成。 使用自定义类型(结构或类)定义类型实体(结构变量或类对象)的格式相同。在面向对象的程序设二者的不同之处表现在: 使用 struct 定义的结构类型的定义体中只包含数据成员,而使用 class 定义类类型的定义体中既包含数据成员,还包含处理这些数据的操作成员函数。 结构
4、类型的成员均可以从类型外直接cout “num: ” stud1.num endl; cout “name: ” endl; cout “sex: ” stud1.sex endl;。例如:而类类型的成员是否能从类外直接取决于成员的权限,例如,Student 中的数据成员就不能从类外直接,而输出显示这些数据只能通过成员函数( stud1.display(); )实现。3.1.2 类类型成员的权限为了实现类对象的封装性(数据隐藏和提供接口)类类型定义为类成员提供了私有和公有两种基本权限供用户选择。1 私有成员权限:只限于类成员。 关键字:private或从定义体开始的缺省声
5、明。例如,下面的 Student 定义与前面的 Student定义等价的:class Studentprivate:int num;char name20; char sex;public:void display() cout “num: ” num endl; cout “name: ” name endl; cout “sex: ” sex endl; 私有段:从 private: 开始至其它权限之间所有成员组成的代码段。例如 Student 定义中从private: 开始到 public: 之间的所数据成员。 成员种类:数据成员和成员函数。2 公有成员权限:类成员和类外的任何。 关键字
6、:public。 公有段:从 public: 至其它成员组成的代码段。 成员种类:数据成员和成员函数。之间所有成员使用私有成员来隐藏由类对象操作的数据,然后提供相应的公有成员函数来和操作这些数据,而访问和操作这些数据实现细节通常是被隐藏起来的。除了私有和公有两种基本权限外,类类型定义还提供了类成员和派生类成员,而不类外的保护成员权限(protected),以满足实现继承性的需要。为了使 C+ 语言所设计程序中的数据都能实现数据抽象,并能与 C 语言设计的程序中的数据兼容, C+ 仿照类类型定义的功能,对 struct 定义的结构体类型功能进行如下扩展: 定义体中也可以包括对数据成员进行处理和操
7、作的成员函数。 添加了与类类型定义相同的成员权限功权限为能,但仍然保留了缺省公用的基本特点。表示成员的扩展后的 struct 可以定义与类类型效果相同的结构类型,例如:struct Studentprivate:int num;char name20; char sex;public:void display() cout “num: ” num endl; cout “name: ” name endl; cout “sex: ” sex endl;该结构类型与先前使用 class 定义的 Student 类型的效果完全相同。请注意,这并不意味着可以用 struct 替代class,因为使用
8、 class 定义的类类型的缺省私有性质能更方便、安全地实现面向对象程序设计对类对象的要求,因此强烈建议使用 class 建立数据类型;而只有希望所建立类型的全部成员都是公有权限时,使用struct 建立结构类型比较方便。3.1.3 类类型的构造类类型定义为所定义的数据类型建立了一个明确的 边界,类定义体中的私有成员(数据成员和成员函 数)和公有成员函数的实现细节均被封装在此边界 内,使得这些类成员和实现细节无法从类对象外被访问,从而受到保护。同时对类公有成员(数据成员和成员函数)的和调用又为类对象之间的通讯提供了接口,使得类对象成为一个既的抽象数据实体。下面以一个简单类类型的构造:安全又操作
9、方便人类为例说明 确定 改变、人状态的属性:是位置和面对的方向和显示人状态的操作:有、转向、前进、显示状态等。class Hominoidint dirction;/人的方向人的位置point location; public:void turnLeft(); void turnRight(); bool advance();point location(point loc); bool facingWall();void display();/ 向左转90度/ 向右转90度/ 前进一步/是否面对墙壁/ 显示当前位置该定义所建立的人类的构造可以形象地用下图表示,它很象一个封装好的器件。dire
10、ction 属性操作locationJava 的类定义与 C+ 的类定义在格式上基本相同,但有两点是不一样的: 成员的权限必须逐个显式说明; 类定义结束不要分号“;”。例如:class Userprivate String name; private int age;public User(String str int yy) name = str; age = yy; 3.2 成员函数的定义1 成员函数的性质类的成员函数在和定义的格式上以及用法和作用上与一般函数基本一致。但由于成员函数是属于某一个类的成员,因此它与一般函数的区别表现: 作用域在类定义体所确定的边界内,即可以本类的任何成员(私
11、有和公有的数据和函数)。 需要根据功能和作用指定成员函数的权限,一般情况下,将向类外提供操作功能的成员函数指定为 public,将只为类内提供服务功能的成员函数指定为 private,将只为类内和派生类提供服务功能的成员函数指定为 protected。2 成员函数的和定义形式 在类定义体内定义成员函数的实现代码。这种形式下,函数定义的首部将起到函数原型的作用,因此无须成员函数定义之前的原型class pointint x, y;public:void setpoint(int vx, int vy) x = vx; y = vy; ;。例如: 在类定义体内成员函数,而在类定义体外定义成员函数的
12、实现代码。采用这种定义形式的时,类定义体外的定义代码必须满足: 在成员函数名之前应缀上所属的类名:,“:”是作用域运算符,以便说明函数的作用域。 成员函数定义的首部(函数的返回类型、函数名和参数表列)必须与在类定义体中的该函数的原型一致。例如:class point int x, y;public:void setpoint(int, int);void point:setpoint(int vx, int vy)x = vx; y = vy;由于第 种形式不仅可以减少类定义体的代码长度,使类定义体清晰、可读性好;更重要的是有助于类的操作接口与操作实现细节相分离,并隐藏细节。因此,提倡采用该形
13、式定义类成员函数。3 类的内置(内联)成员函数定义方式: 隐式定义 函数定义在类定义体中,此时只要函数的实现代码符合内置函数的定义要求,该 成员函数就会自动被定义内置函数,而说明内置 函数的关键字 inline 可以忽略。例如:class pointint x, y;public:void setpoint(int vx, int vy) x = vx; y = vy; / 内置函数;其中成员函数 setpoint 定义的首部与加缀 inline 的首部 “inline void setpoint(int vx, int vy)” 等效。 显式定义 函数在类定义体中,而函数定义在类定义体外,此
14、时函数定义的首部必须冠以关键字 inline 说明此函数是内置的。例如:class pointint x, y;public:inline void setpoint(int, int);/ 内置函数;inline void point:setpoint(int vx, int vy) / 内置函数定义x = vx; y = vy;需要特别注意的是:由于调用内置函数需要将内置函数的目标代码到它被调用的位置,因此编译器在进行内置函数的调用编译时,必须能获得被调内置函数的目标代码。这就需要在调用内置函数的源代码文件中必须包含被调用内置函数的定义代码的源代码文件。也就是说,如果某个被调用的内置成员函
15、数定义在类定义体中,该类定义体代码被保存在一个头文件中,例如 “student.h”,则调用该内置函数的源文件应添加预编译命令 #include “student.h”。如果该内置函数 定义在类定义体外,代码包含在类实现文件中,例如“student.cpp”,则调用该内置函数的源文件应添加预编译命令 #include “student.cpp”。4 成员函数的空间从类类型的定义不难看出,类的数据成员(对象属性)中保存的数据值代表了类对象的状态,决定了 该类的不同对象的差别,因此当类对象创建时,每 个类对象都必须独占一份(个数相同、类型相同)数据成员空间,用于保存区别于其他对象的状态;而类的成员
16、函数描述了该类所有对象的统一行为操作,而操作结果(行为表现)的差异取决于不 同对象的状态,因此,成员函数的运行代码被在与数据成员空间不同的代码空间中,被该类的所有对象共享。例如:由于语句 Student stud1, stud2, stud3; 执行所创建的 3 个 Student 对象在程序运行空间中占用内存的大小和位置的状态示意如下:stud1stud2 stud3程序代码区Student:Student()的运行代码Student:Student()的运行代码Student:display()的运行代码程序数据区numnamesexnumnamesexnumnamesex3.3 类与对象
17、3.3.1 类与对象的关系 类是一组具有相同属性和行为的对象的抽象,是创建对象的模板,是用户使用 class 创建的自定义类型。类一旦创建,其作用可与系统预定义类型(例如,int、double 等)类比。 对象是类的实例,创建类的对象可以与创建预定义类型的变量(例如,int x;、double d; 等)类比。 类只是提供了该类对象的创建和使用的方法和规则,因此类本身不占用内存。创建类对象时将按类定义提供的方法和规则,在内存中为类对象分配空间,因此,封装是对类对象而言的。3.3.2 定义对象的方法:1 先创建类类型,使用时再定义对象大多数情况均采用该方法定义类对象。这样创建的 类对象的生存周期
18、取决于创建的位置。例如:class Student void main();Student Zhang, Li;/ 创建 Student 局部对象虽然 C+ 也将上述的类对象定义语句写成:class Student Zhang, Li; (C 风格)但不能体现 C+ 面向对象的设计风格,且不方便简洁,所以不提倡。2 在创建类类型的同时定义对象。使用这种方法定义的类对象的生存周期取决于类类 型的创建位置。例如:class Studentint num;char name20; char sex;public:void display() cout “num: ” num endl; cout “
19、name: ” name endl; cout “sex: ” sex 成员名;其中成员名必须是指针所指对象的所属类的公有数 据成员名或公有成员函数名。例如:class point int x, y; public:setpoint(int vx, int vy) x = vx; y = vy; ;void fun() point *p=new point; / p 指向动态创建的 point 对象p-setpoint(10, 10); / 给 p 所指对象的坐标 x, y 赋值.3 通过对象的一般形式:对象对象成员名.成员名;其中成员名必须是对象名所对象的所属类的公有数据成员名或公有成员函数
20、名。例如:class point int x, y; public:setpoint(int vx, int vy) x = vx; y = vy; ;void fun() point pt, &p = pt; p.setpoint(10, 10);./ p/ 给 ppoint 对象 pt的对象的坐标 x, y 赋值3.3.4 成员名由于类成员作用域在该类定义体所限定的边界内,因此,不同类中具有同名的成员是例如:产生二义性。class realSet/ 定义一个实数集合类public:void print();class intSet/ 定义一个整数集合类public:void print()
21、;void fun()intSet is; realSet rs; is.print();rs.print();/ 调用 intSet 类中的 print() 函数/ 调用 realSet 类中的 print() 函数显然引起二义性错误。3.4 构造函数使用类定义对象时,需要一种操作,使所定义的对象与类的定义域相关。实现这一操作的成员函数称为构造函数,该函数要完成的操作包括: 依据类数据成员的个数和类型为对象分配内存; 根据需要为对象的数据成员进行必要的初始化。构造函数是类必须拥有的特殊成员函数,该函数从定义形式到使用场合和方法上都与一般成员函数不同,这些差异表现在以下几个方面: 构造函数名必
22、须与类名相同,否则编译器将会把它当作一般成员函数对待。例如:class Studentpublic:Student();Student:Student() 构造函数没有返回值,因此,时都不能说明它的返回类型;和定义构造函数 构造函数的功能是将对象初始化,因此构造函数一般只对数据成员进行初始化和必要的辅助操作,而 不提倡做与初始化无关的操作。 系统总会为类提供一个隐含的缺省构造函数。该构造函数实际上是一个空定义体函数,因此只能为对象分配空间而不能为数据成员进行初始化。在大多数情况下,数据成员的初始化操作是十分必要的,因此通常需要显式定义构造函数。构造函数 一旦显式定义,缺省构造函数将被覆盖。 在
23、程序运行过程中,类对象是在进入其作用域时才被创建的。也就是说,此时类对象的构造函数被调 用。 构造函数在类对象创建时由系统自动执行,不需要用户调用,也不能由用户调用。例如:Student stud1;stud1.Student();/ 系统调用构造函数创建 stud1/ 企图用一般成员函数的调用方法/ 调用构造函数,因此是错误的。 不能为构造函数定义函数指针,也不能获取构造函数的调用地址。 基类的构造函数不能被派生类继承。 构造函数不能为虚函数。例3-1 定义一个整数队列类,使用由系统隐含提供的缺省构造函数创建整数队列,并测试队列功能。1 问题分析 用例分析向队列中装入整数从队列中取出整数用户
24、 类图描述2 详细设计 类设计 qurue 类类定义class queueint q100;int head, trail; public:void qput(int i); int qget();/ 队列空间/ 队列头、尾指示/ 队列操作/ 队列取出操作算法描述成员函数 qput 的 N-S 流程图:成员函数 qget 的 N-S 流程图: 类对象创建和使用main 函数的 N-S 流程图:实例3-1程序3.4.1 参数化的构造函数与其他成员函数一样,构造函数也可以有参数。通过这些参数为类对象的数据成员传递初值。例如:class pointint x,y; public:point(int
25、vx, int vy);void offset(int ax, int ay);/带参数的构造函数;point:point(int vx, int vy)x = vx; y = vy;main()point p(10,20);/ 用传递来的实参对 x,y 赋初值/ 定义对象,并传递初值注意,不要将使用参数创建类对象的代码写成:point p = point(10, 20);3.4.2 构造函数的重载在一个类中定义多个参数不同构造函数,即构造函数重载。这样就为在不同情况下创建对象的特定初始化需要提供了实现。也就是说,在类对象定义时,编译器可以依据创建对象所需要的参数差异确定调用构造函数的哪一个版
26、本来创建类对象。例3-1-1 定义一个有两个构造函数的类,并使用不同构造函数定义对象。3.4.3 使用缺省参数值的构造函数与其他函数一样,构造函数的参数也可以具有缺省值,表示类对象的某些属性在大多数情况下是预先可以确定的缺省状态,例如计数器的初值一般为“0”、战士的士”等多数为“男”、大学教师的学位一般为“硕等。构造函数的缺省参数值的定义和使用规则与其他带缺省参数值的函数相同。例3-1-2 描述了如何,定义和使用带有缺省参数值归纳构造函数使用缺省参数值的编程要点是: 指定缺省参数值只能在构造函数的中,而不能出现在构造函数定义的首部。构造函数定义在类定义体中的情况除外。函数中的参数可以省略参数名
27、,此时指定缺省参数值的格式为:类型名 = 缺省值。例如:Box(int = 10, int = 10, int = 10); 如果构造函数的全部参数都指定了缺省值,应该避免再定义一个无参数的构造函数。因为在定义构造 函数时,编译器会认为可能是重复定义。例如:Box();Box(int = 10, int = 10, int = 10);更重要的是定义类对象时,遇到如下情况:Box box1;编译器无法确定调用哪一个构造函数版本来创建类 对象。 如果构造函数的全部参数都指定了缺省值,就容易在重载构造函数时造成二义性。例如:Box(int = 10, int = 10, int = 10); Bo
28、x();Box(int, int);因此,应避免全部参数都指定了缺省值。例如:Box();Box(int, int = 10, int = 10); Box(int, int);3.4.4 用参数初始化表对数据成员初始化所谓参数初始化是指系统在为类对象的各个数据成员分配内存空间的同时能按照用户通过参数指定的值为数据成员赋值,而不是在各个数据成员的内存空间分配完成后,再对它们进行赋值。这就需要通过一种语法格式,即参数初始化表,使编译器能按照上述要求实现对类对象的各个数据成员的初始化。构造函数参数初始化表的一般形式为:: 基类初始化列表,属性初始化列表其中基类初始化列表只有在派生类的构造函数初始化
29、表才会存在,这一部分将在第五章中介绍。属性初始化列表由若干个属性初始化项组成,项间用“,”隔开:属性初始化项1, 属性初始化项2, 属性初始化项n每个属性初始化项的一般格式为:属性名(参数列表)不难看出,属性初始化项的含义是调用相应的属性类的具有参数的构造函数用于属性对象的创建和赋初值操作。这从另一个角度告诉我们,一个构造函数的定义中没有出现初始化表意味着使用了隐含的初始化表,该 表的功能是分别调用了相应类的无参数(或有缺省参 数值)构造函数完成类对象的基类部分和各个属性对 象创建和赋初值。例3-1-3 是将例3-1-1中的类构造函数改写为使用参数初始化表实现类对象各数据成员的初始化。虽然两个
30、实例中对类对象的数据成员初始化的结果 是完全相同的,但两种初始化方法对数据成员的赋值的时间和方法是完全不同的。在构造函数定义中使用初始化表另一个非常重要的就是对于类对象的常数据成员、数据成员的初始化就必须在创建的同时进行赋值操作,而不能在函数体中进行赋值。例如:class A public:A(int i);const int& ref; private:const int a;A:A(int i) : a(i), ref(a) / 常数据成员/ 常数据成员3.4.5 拷贝构造函数拷贝构造函数是一个特定的构造函数。该构造函数与其他构造函数在形式上的差别仅在于函数的参数必须是同类型对象的常。拷贝
31、构造函数的原型格式如下:类型名(const 类型名&名);拷贝构造函数的功能是创建一个新对象,并将参数所对象的各个数据成员值到新对象的对应的数据成员域中。系统会为每个类缺省定义一个拷贝构造函数,也允许用户定义一个拷贝构造函数,用以取代缺省的拷贝 构造函数。一般情况下,使用系统定义的缺省拷贝构造函数就可以满足类对象的操作,但在有些情况下,用户必须定义class stringint length; char *str;public:string(int len);的拷贝构造函数。例如:/ 指针数据成员string:string(int len)length = len;str = new char
32、len + 1;/ 指针数据成员指向动态分配的内存空间main()string s1(10); string s2(s1);/ 创建一个 string 对象 s1/s1 到新 string 对象 s2s1s2在这种情况下,s1 和 s2 的指针数据成员 str 指向了同一内存空间,使得通过 str 对该内存空间的任何操作都不能保持应有的性。更严重的是当 s1 和 s2 之中有一个被撤消时,在堆中分配的内存空间被撤消回收,使得另一个 string 对象的指针数据成员 str 成为无效指针,任何通过该指针的操作均为致严重的运行错误。造成这一问题的操作,会导是系统提供的缺省拷贝构造函数不能strin
33、g 对象。因此,在这种情况下必须定义的拷贝构造函数:string:string(const string &s)length = s.length;str = new charlength + 1; strcpy(str, s.str);Java 没有 C+ 那种含义的指针,也没有拷贝构造函数。同时,对象的撤消是由收集器完成的,因此也产生像 C+ 中那样的问题。当然在 Java 中也可以用赋值运算符 “=” 来进行对象赋值,但是,这并不意味着一个简单赋值操作所具有的直觉含义。例如:class User public string name;class Testpublic static voi
34、d main(String args) User u1 = new User(“ariel”,112);System.out.println(); User u2 = u1; = “muriel”;System.out.println();/ ariel/ muriel显然,这里的 u2 = u1 只是对对象的。由于u1 和 u2同一个 User 对象,所以才会导致修改 实际上等价于 对 的修改(这与 C+中两个指针指向同一个对象的情况类似)。如果要完成直觉意义上的,就必须通过实现 User 类的克隆接口 Cloneable
35、 后,调用逐字节的克隆函数 clone()完成。例如:class User implements Cloneablepublic string name;class Testpublic static void main(String args) User u1 = new User (“ariel”,112);System.out.println (); User u2 = (User)u1.clone(); = “muriel”;System.out.println ();/ ariel/ ariel3.5 析构函数对象撤消时,也需要一种操作,使
36、被撤消的对象从 程序的数据区中合法消失。实现这一操作的成员函数 称为析构函数,该函数要完成的操作包括: 回收被撤消对象数据成员所占用的内存; 根据需要完成回收被撤消对象数据成员所占内存之前的必要操作。析构函数也是类必须拥有的特殊成员函数,该函数从定义形式到使用场合和方法上都与构造函数相似,主要特点表现在以下几个方面: 析构函数名必须是类名加字符 “” 前缀,否则编译器将会把它当作一般成员函数对待。例如:class Studentpublic:Student();Student:Student() 析构函数没有返回值,因此,和定义析构函数时都不能说明它的返回类型; 系统总会为类提供一个隐含的缺省
37、析构函数。该析构函数实际上是一个空定义体函数,因此只能撤消回收对象所占用的空间。如果在对象被撤消之前无须做必要的预处理操作,则可以放心使用缺省析构函数。但在有些情况下,则必须定义析构函数。析构函数一旦显式定义,缺省析构函数将被覆盖。例如:class stringint length;char *contents; public:string(char *s);string();/构造函数析构函数类 string 的对象在撤消之前需要先检查 contents 是否指向有效的内存空间,如果是,则回所占用的内存 空间,因此必须重新定义析构函数,取代系统隐含 定义的缺省构造函数。string:stri
38、ng(char *s)if(s)length = strlen(s);/ 定义构造函数contents = new charlength + 1;strcpy(contents, s);/ 分配/ 字串赋值elselength = 0;contents = 0;/ 设置指针数据成员为空string:string()if(contents)delete contents;/ 定义析构函数/contents 指向的内存空间 在程序运行过程中,类对象是在其作用域时才被析构的。也就是说,此时类对象的析构函数被调用。 析构函数在类对象撤消时由系统自动执行,不需要用户调用,也不能由用户直接调用。 不能为析
39、构函数定义函数指针,也不能获取析构函数的调用地址。 基类的析构函数不能被派生类继承。 析构函数可以为虚函数,并且提倡为虚函数(详细在第六章 运行多态性中讲述)。3.6 对象的动态创建和与预定义类型一样,自定义类型也可以使用运算符new 动态创建对象和使用运算符 delete 撤消类对象。例3-2 描述了动态创建、撤消和使用 point 类对象。注意:1 使用无参数或具有缺省参数值的构造函数动态创建类对象(即创建对象时不传递初始值)的格式为:例如, point *p = new point;new 类型名;而不应写成:new 类型名();例如, point *p = new point();上述
40、格式与动态创建系统预定义类型变量的格式完全一致(预定义类型无缺省初始值)。例如:int *p = new int;2 使用有参数的构造函数动态创建类对象(即创建对象时传递初始值)的格式为:new 类型名(初始值);例如,point *p = new point(10,20);上述格式与动态创建系统预定义类型变量并传递初始值的格式完全一致。例如:int *p = new int(10);例3-3 通过构造函数对对象数组进行初始化。对象数组初始化的方法一般有两种:1 使用缺省构造函数创建对象数组后,调用一个专门用于初始化的成员函数对数组中的每个对象分别进 行初始化。该方法虽然必须分两步完成对象数组
41、的 创建和初始化,但可以将对象数组中的元素初始化 为任意值。2 定义一个带缺省参数的构造函数。在创建对象数组的同时,由数组中的每个对象构造函数的缺省值完 成对象的初始化。使用该方法创建和初始化对象数 组简单、方便,但只能将对象数组中的每个元素初 始化为固定的缺省值。3.7 对象的赋值与1 对象的赋值对象的赋值只能发生在同类型对象之间的,这与系 统预定义类型变量的赋值是一致的。对象赋值的一 般格式为:对象名1 = 对象名2;赋值操作是由赋值运算符“ =” 完成的, 该运算符(函数)的功能是将对象名2所指示对象的各个数据成员 值依次传递给对象名1所指示对象的各个数据成员, 使对象1与对象2完全相同
42、。系统会为每一个自定义类型自动添加一个隐含的缺省赋值运算符,因此一般的自定义类型不必显式定义赋值运算符。但如果类定义中包含有指针类属性(3.4.5 拷贝构造函数中已经讨论这种情况),则必须显式定义赋值运算符用于取代隐含的缺省赋值运算符。如何定义赋值运算符将在第五章中讨论。例3-2-1 描述了使用缺省赋值运算符完成对象的赋值操作。2 对象的对象的是指按照一个已经存在的对象创建一个与该对象完全相同的新对象。显然对象的操作是由类的拷贝构造函数完成的,的一般形式为:一个已有对象类型名 对象2(对象1);例如,Box box2(box1);在 C+ 中上述也适用于预定义类型,即每个预定义类型都有一个隐含
43、的拷贝构造函数。例如,int a(10), b(a);C+ 还提供了另外便用户的形式,即用赋值符号代替括号调用类的拷贝构造函数:类型名 对象2 = 对象1; 例如,Box box2 = box1;显然,这种式是一致的。形式与预定义类型变量赋值定义形例如,int a = 10, b = a;程序中需要对象操作的情况有三种: 用户定义一个与已有对象完全一致的新对象。 函数调用时,系统需要 函数返回时,系统会被传递的实参对象。被返回的操作结果。3.8 与对象有关的指针指针变量可以用于指向任何预定义类型变量,当然 也可以指向自定义类型对象。不仅如此,指针变量还 可以指向对象的类成员。1 指向对象的指针
44、定义指向对象的指针变量的一般形式:类型名 *对象指针名;例如,Box *pt;显然,这与定义预定义类型指针的形式是完全一致的。同样,指针的使用形式也是相同的。例如:pt = new Box;pt-volume();/ 与 (*pt).volume(); 等价2 指向对象成员的指针对象的成员有数据成员和成员函数两种,因此指向 对象成员的指针也有两种。 指向数据成员的指针定义指向数据成员的指针变量的一般形式: 类型名 *数据指针名;显然,这与定义预定义类型指针是完全一致的。 同样,指针的使用形式也是相同的。例如: class Time public:int hour, minute, sec; v
45、oid show();void Time:show()cout hour “:” minute “:” sec *成员函数指针)(实参列表);例如,Time *pt = &time;(pt-*pf)();3 this 指针this 指针是类成员函数拥有的一个隐含指针,它指向该成员函数被调用时,操作所施加的类对象地址,实现不同对象的相为的表现差异。类对象1:类对象2类对象n成员函数通过 this 指针可以所指对象中的类成员,数据成员的格式可写为:this-数据成员名成员函数的格式可写成:this-成员函数名(参数列表)例如:class exth int i;public:void load(in
46、t val) this-i = val; int get() return this-i; ;void main()exth obj; obj.load(100); cout x = x;this-y = y;当然,这种问题也可以用如下方法解决:point:point(int x, int y)point:x = x;point:y = y;为了进一步了解成员函数被调用时 this 指针是如何在“幕后”工作的,我们再来分析一段程序:class abc private:char a; int b;public:void init(char ma, int mb) a = ma; b = mb;
47、;int main()abc ob; ob.init(x, 12);return 0;分析:在 main() 中,abc 类成员函数 init 通过类对象ob 被调用的:ob.init(x, 12);C+ 是如何使 this 指针指向对象 ob 的呢?编译器在编译过程中对上述语句经过如下的转换: 首先将成员运算符“.”之前的对象 ob 的地址作为实参传给函数 init,则语句变为:init(&ob, x, 12); 虽然成员函数 init 的原型中没有相应的形参,但程序编译时,编译器将该函数的原型和定义隐含 转换成以下形式:init(abc* this, char ma, int mb) this-a = ma; this-b = mb; 显然,该成员函数被调用时,第一个形参应是调用该成员函数的对象地址,因此当对象ob 调用成员函数 init 时,形参 this = &ob。确保成员函数init
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 安全教育鼻出血培训课件
- 防城区那巴水车、那巴村、板蒙里林沟采砂工程项目环境影响报告表
- 灯具工程配套方案(3篇)
- 猫咪面具课件教学
- 农业智能化转型2025年灌溉监测一体化系统建设与创新
- 猫咪画毛衣课件
- 农业无人机租赁市场2025年行业竞争格局与市场潜力分析
- 工程保修工作方案(3篇)
- 电厂钢架改造工程方案(3篇)
- 安全教育摩托车培训课件
- GB/T 5780-2016六角头螺栓C级
- 福安蟾溪林场储备林2023年作业设计
- GA/T 1471-2018居民身份证制作中心(所)建设规范
- 学生课程免考(修)申请表(模板)
- 粘膜免疫 2课件
- 电子课件-《可编程序控制器及其应用(三菱-第三版)》-A04-1724-课题一-可编程序控制器基础知识
- 统计业务知识(统计法规)课件
- 艾滋病个案流行病学调查表
- 广告策划与创意课件-2
- 地质勘察任务书模板
- 全国中心血站上岗证考试题库
评论
0/150
提交评论