第7单元类和对象(I) 第7单元类和对象(I) 本单元教学目标 介绍面向对象程序设计方法的基本原理以及类和对象的概念。 教学要求 掌握面向对象的程序设计思想,类和对象的概念,以及类的声明方法和对象的引用。 授课內容 71面向对象的程序设计 在面向对象的程序设计技术( OOP: Object Oriented Programming)出现前,程序员们一 般采用面向过程的程序设计方法。面向过程的程序设计方法采用函数(或过程)来描述对数 据结构的操作,但又将函数与其所操作的数据分离开来。作为对现实世界的抽象,函数和它 所操作的数据是密切相关、相互依赖的:特定的函数往往要对特定的数据结构进行操作;如 果数据结构发生改变,则必须改写相应的函数。这种实质上的依赖与形式上的分离使得用面 向过程的程序设计方法编写出来的大程序不但难于编写,而且难于调试和修改 面向对象程序设计从所处理的数据入手,以数据为中心而不是以功能为中心来描述系 统。数据相对于功能而言具有更强的稳定性。面向对象程序设计与结构化程序设计最大的区 别就在于,前者首先关心的是所要处理的数据,而后者首先关心的是功能。 面向对象程序设计是一种围绕真实世界的概念来组织模型的程序设计方法,它采用对象 来描述问题空间中的实体。关于对象这一概念,目前还没有统一的定义。一般的认为,对象 是包含现实世界物体特征的抽象实体,反映了系统为之保存信息和(或)与之交互的能力。 对象是一些属性及服务的封装体,在程序设计领域,可以用“对象=数据+作用于这些数据 上的操作”这一公式来表达 类是具有相同操作功能和相同的数据格式(属性)的对象的集合,可以看作抽象数据类 型的具体实现。从外部看,类的行为可以用新定义的操作(方法)加以规定。类是对象集合 的抽象,规定了这些对象的公共属性和方法;对象是类的一个实例。例如,苹果是一个类, 而放在桌上的那个苹果则是一个对象。对象和类的关系相当于一般的程序设计语言中变量和 变量类型的关系 消息是向某对象请求服务的一种表达方式。对象内有方法和数据,外部的用户或对象对 该对象提出的服务请求,可以称为向该对象发送消息。 面向对象的编程方法具有四个基本特征:
第 7 单元 类和对象(I) - 131 - 第 7 单元 类和对象(I) 本单元教学目标 介绍面向对象程序设计方法的基本原理以及类和对象的概念。 教学要求 掌握面向对象的程序设计思想,类和对象的概念,以及类的声明方法和对象的引用。 授课内容 7.1 面向对象的程序设计 在面向对象的程序设计技术(OOP: Object Oriented Programming)出现前,程序员们一 般采用面向过程的程序设计方法。面向过程的程序设计方法采用函数(或过程)来描述对数 据结构的操作,但又将函数与其所操作的数据分离开来。作为对现实世界的抽象,函数和它 所操作的数据是密切相关、相互依赖的:特定的函数往往要对特定的数据结构进行操作;如 果数据结构发生改变,则必须改写相应的函数。这种实质上的依赖与形式上的分离使得用面 向过程的程序设计方法编写出来的大程序不但难于编写, 而且难于调试和修改。 面向对象程序设计从所处理的数据入手,以数据为中心而不是以功能为中心来描述系 统。数据相对于功能而言具有更强的稳定性。面向对象程序设计与结构化程序设计最大的区 别就在于,前者首先关心的是所要处理的数据,而后者首先关心的是功能。 面向对象程序设计是一种围绕真实世界的概念来组织模型的程序设计方法,它采用对象 来描述问题空间中的实体。关于对象这一概念,目前还没有统一的定义。一般的认为,对象 是包含现实世界物体特征的抽象实体,反映了系统为之保存信息和(或)与之交互的能力。 对象是一些属性及服务的封装体,在程序设计领域,可以用“对象=数据+作用于这些数据 上的操作”这一公式来表达。 类是具有相同操作功能和相同的数据格式(属性)的对象的集合,可以看作抽象数据类 型的具体实现。从外部看,类的行为可以用新定义的操作(方法)加以规定。类是对象集合 的抽象,规定了这些对象的公共属性和方法;对象是类的一个实例。例如,苹果是一个类, 而放在桌上的那个苹果则是一个对象。对象和类的关系相当于一般的程序设计语言中变量和 变量类型的关系。 消息是向某对象请求服务的一种表达方式。对象内有方法和数据,外部的用户或对象对 该对象提出的服务请求,可以称为向该对象发送消息。 面向对象的编程方法具有四个基本特征:
第7单元类和对象(I) 1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与 当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,忽略与主题 无关的细节。例如,在设计一个学生成绩管理系统的过程中,考察学生张三这个对象时,我 们只关心他的班级、学号、成绩等,而他的身高、体重等信息就可以忽略。抽象包括两个方 面,一是过程抽象,二是数据抽象。过程抽象是指任何一个明确定义功能的操作都可被使用 者看作单个的实体看待,尽管这个操作实际上可能由一系列更低级的操作来完成。数据抽象 定义了数据类型和施加于该类型对象上的操作,并限定了对象的值只能通过使用这些操作修 改和观察。 2.封装:封装是面向对象的特征之一,是对象和类概念的主要特性。封装把过程和数 据封藏起来,对数据的访问只能通过已定义的界面。面向对象技术的基本概念就是现实世界 可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象 旦定义了一个对象的特性,则有必要决定这些特性的可见性,即哪些特性对外部世界是可 见的,哪些特性用于表示内部状态。通常,应禁止直接访问一个对象的实际表示,只能通过 操作接口访问对象,这称为信息隐藏。事实上,信息隐藏是用户对封装性的认识,封装则为 信息隐藏提供支持。封装保证了模块具有较好的独立性,使得程序维护修改较为容易。对应 用程序的修改仅限于类的内部,因而可以将应用程序修改带来的影响减少到最低限度。 3.继承:继承是一种联结类与类的层次模型。继承允许和鼓励类的重用,提供了一种 明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类 继承了原来类的特性,新类称为原来类的派生类(子类),而原来类称为新类的基类(父类)。 派生类可以从其基类那里继承方法和成员变量,当然也可以对之进行修改或增加新的方法使 之更适合特殊的需要。这也体现了大自然中一般与特殊的关系。继承性很好地解决了软件的 可重用性问题。 4.多态性:多态性是指允许不同类的对象对同一消息作出响应。例如同样的加法,把 两个时间加在一起和把两个整数加在一起的内涵肯定完全不同。多态性包括参数化多态性和 包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用 程序函数同名问题。 面向对象程序设计具有许多优点:开发时间短,效率高,可靠性高,所开发的程序更强 壮。由于面向对象编程的编码可重用性,可以在应用程序中大量采用成熟的类库,从而缩短 了开发时间,使应用程序更易于维护、更新和升级。继承和封装使得应用程序的修改带来的 影响更加局部化。 72类与对象 721类的声明 C++类的结构比较复杂,可以将其看成是一种既包含数据又包含函数的数据类型。显然, 描述不同编程对象的类应有不同的内部结构,所以在使用类来声明对象前应先说明其结构 声明一个类的一般形式为: lass<类名> 成员表>; public
第 7 单元 类和对象(I) - 132 - 1. 抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与 当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,忽略与主题 无关的细节。例如,在设计一个学生成绩管理系统的过程中,考察学生张三这个对象时,我 们只关心他的班级、学号、成绩等,而他的身高、体重等信息就可以忽略。抽象包括两个方 面,一是过程抽象,二是数据抽象。过程抽象是指任何一个明确定义功能的操作都可被使用 者看作单个的实体看待,尽管这个操作实际上可能由一系列更低级的操作来完成。数据抽象 定义了数据类型和施加于该类型对象上的操作,并限定了对象的值只能通过使用这些操作修 改和观察。 2. 封装:封装是面向对象的特征之一,是对象和类概念的主要特性。封装把过程和数 据封藏起来,对数据的访问只能通过已定义的界面。面向对象技术的基本概念就是现实世界 可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。 一旦定义了一个对象的特性,则有必要决定这些特性的可见性,即哪些特性对外部世界是可 见的,哪些特性用于表示内部状态。通常,应禁止直接访问一个对象的实际表示,只能通过 操作接口访问对象,这称为信息隐藏。事实上,信息隐藏是用户对封装性的认识,封装则为 信息隐藏提供支持。封装保证了模块具有较好的独立性,使得程序维护修改较为容易。对应 用程序的修改仅限于类的内部,因而可以将应用程序修改带来的影响减少到最低限度。 3. 继承:继承是一种联结类与类的层次模型。继承允许和鼓励类的重用,提供了一种 明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类 继承了原来类的特性,新类称为原来类的派生类(子类),而原来类称为新类的基类(父类)。 派生类可以从其基类那里继承方法和成员变量,当然也可以对之进行修改或增加新的方法使 之更适合特殊的需要。这也体现了大自然中一般与特殊的关系。继承性很好地解决了软件的 可重用性问题。 4. 多态性:多态性是指允许不同类的对象对同一消息作出响应。例如同样的加法,把 两个时间加在一起和把两个整数加在一起的内涵肯定完全不同。多态性包括参数化多态性和 包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用 程序函数同名问题。 面向对象程序设计具有许多优点:开发时间短,效率高,可靠性高,所开发的程序更强 壮。由于面向对象编程的编码可重用性,可以在应用程序中大量采用成熟的类库,从而缩短 了开发时间,使应用程序更易于维护、更新和升级。继承和封装使得应用程序的修改带来的 影响更加局部化。 7.2 类与对象 7.2.1 类的声明 C++类的结构比较复杂,可以将其看成是一种既包含数据又包含函数的数据类型。显然, 描述不同编程对象的类应有不同的内部结构,所以在使用类来声明对象前应先说明其结构。 声明一个类的一般形式为: class <类名> { private: <成员表>; public:
第7单元类和对象(I) 成员表 <成员表> } 其中关键字clas指出下面要声明的是一个类,<类名>是程序员为所声明的类起的名字 <成员表>由一个个该类成员的声明组成,这些成员可以是变量(数据成员),也可以是函数 (成员函数);关键字 private引出的成员叫做私有成员,对私有成员的访问权限制在该类的 内部,即只允许该类中的成员函数访问。由于类成员被默认为私有的,所以该关键字可以省 略;关键字 public引出的成员叫做公有成员,公有成员则允许该类以外的函数访问;而关键 字 protected引出的成员叫做保护成员,保护成员的访问权限将在第8单元介绍 例7-声明一个 Person类,用来说明人类对象 说明:将 Person类的声明放在头文件中。为项目添加头文件的方法与添加源代码 文件的方法类似,建立项目后,使用 Developer Studio的菜单选项Fle/New.,在File选项 卡中选择CC++ Header file项,并在对话框右面的Fle框中填写文件名(可与项目名相同), 然后按OK键即可生成一空白头文件。然后输入如下代码 程序 / Example7-1( Person.h):声明 Person类 /类 Person的声明 class person private char m strName [20] nt publ void Register(char *Name, int Age, char Sex) void Get Name(char *Name) GetAgeo Get Sex 作为一个人,可能有许多特征:姓名、性别、年龄、身高、体重、民族、学历、职业, 类 Person体现了对人的抽象,它集中了人所具有的共性。同时,在该类中还说明了对一个抽象 人的属性进行操作的方法:登录一个人的信息的函数 Register();获取一个人的信息的函数 GetName()、 GetAge()和 GetSex()。该例中,将数据成员声明为私有的以阻止外界对它们 的随意访问,而成员函数则声明为公有的,它们便是外界访问类中数据成员的统一接口。本例 中的 private关键字可以省略。另外,在类的声明中,不同访问权限的成员的书写顺序可以任意 排列。在这种情况下,要注意使用关键字 private,不能随便省略。 在 Visual c++程序中,在声明类的数据成员时,通常在其名前加上前缀“m”,以区别于 普通的变量名。 在声明一个类时应注意:
第 7 单元 类和对象(I) - 133 - <成员表>; protected: <成员表>; … … }; 其中关键字 c1ass 指出下面要声明的是一个类,<类名>是程序员为所声明的类起的名字; <成员表>由一个个该类成员的声明组成,这些成员可以是变量(数据成员),也可以是函数 (成员函数);关键字 private 引出的成员叫做私有成员,对私有成员的访问权限制在该类的 内部,即只允许该类中的成员函数访问。由于类成员被默认为私有的,所以该关键字可以省 略;关键字 public 引出的成员叫做公有成员,公有成员则允许该类以外的函数访问;而关键 字 protected 引出的成员叫做保护成员,保护成员的访问权限将在第 8 单元介绍。 [例 7-1] 声明一个 Person 类,用来说明人类对象。 说 明:将 Person 类的声明放在头文件中。为项目添加头文件的方法与添加源代码 文件的方法类似,建立项目后,使用 Developer Studio 的菜单选项 File/New…,在 File 选项 卡中选择 C/C++ Header File 项,并在对话框右面的 File 框中填写文件名(可与项目名相同), 然后按 OK 键即可生成一空白头文件。然后输入如下代码。 程 序: // Example 7-1(Person.h):声明 Person 类 // 类 Person 的声明 class Person { private: char m_strName[20]; int m_nAge; int m_nSex; public: void Register(char *Name, int Age, char Sex); void GetName(char *Name); int GetAge(); char GetSex(); }; 作为一个人,可能有许多特征:姓名、性别、年龄、身高、体重、民族、学历、职业…, 类 Person 体现了对人的抽象,它集中了人所具有的共性。同时,在该类中还说明了对一个抽象 人的属性进行操作的方法:登录一个人的信息的函数 Register();获取一个人的信息的函数 GetName()、GetAge()和 GetSex()。该例中,将数据成员声明为私有的以阻止外界对它们 的随意访问,而成员函数则声明为公有的,它们便是外界访问类中数据成员的统一接口。本例 中的 private 关键字可以省略。另外,在类的声明中,不同访问权限的成员的书写顺序可以任意 排列。在这种情况下,要注意使用关键字 private,不能随便省略。 在 Visual C++程序中,在声明类的数据成员时,通常在其名前加上前缀“m_”,以区别于 普通的变量名。 在声明一个类时应注意:
第7单元类和对象(I) 类中任何成员都不得用关键字 extern,auto和 register进行修饰 2.不得在类声明中对数据成员使用表达式进行初始化。 72.2成员函数的定义 从例7-1中可以看出,在类的声明中仅给出了成员函数的原型,函数的定义还需在其他地 方(通常每个类的成员函数的定义放在一起构成一个源程序文件)给出。类的成员函数的一般 形式为 类型〉<类名〉::<函数名>(<参数表>) 函数体 其中作用域运算符“”指出成员函数的类属。没有类属的函数称为公共函数,在前面各单元中 用到的函数均为公共函数。 例7-2| Person类成员函数的声明 说明:按例7-1说明的方法添加头文件,输入 Person类的声明。然后为项目添加一源 代码文件,输入以下程序 程序 / Example7-2( Person.cpp): Person类成员函数的定义 #include <string. h> void Person:: Register(const char *name, int age, char sex) strcpy (m s strName, name m sex =(sex =m3?0:1); void Person:: Get Name(char *name strcpy (name, m strName) int Person: GetAgeo return m nAge char Person:: GetSexo return (m nSex==0?'m:'f") 类中的成员函数有时很简单,这样的函数最适合写成内联成员函数以提高程序的执行效率
第 7 单元 类和对象(I) - 134 - 1.类中任何成员都不得用关键字 extern,auto 和 register 进行修饰。 2.不得在类声明中对数据成员使用表达式进行初始化。 7.2.2 成员函数的定义 从例 7-1 中可以看出,在类的声明中仅给出了成员函数的原型,函数的定义还需在其他地 方(通常每个类的成员函数的定义放在一起构成一个源程序文件)给出。类的成员函数的一般 形式为: <类型> <类名> :: <函数名> (<参数表>) { <函数体> } 其中作用域运算符“::”指出成员函数的类属。没有类属的函数称为公共函数,在前面各单元中 用到的函数均为公共函数。 [例 7-2] Person 类成员函数的声明。 说 明:按例 7-1 说明的方法添加头文件,输入 Person 类的声明。然后为项目添加一源 代码文件,输入以下程序。 程 序: // Example 7-2(Person.cpp):Person 类成员函数的定义 #include <string.h> #include “person.h” void Person:: Register(const char *name, int age, char sex) { strcpy(m_strName,name); m_nAge = age; m_nSex = (sex = = ‘m’?0:1); } void Person::GetName(char *name) { strcpy(name, m_strName); } int Person:: GetAge() { return m_nAge; } char Person:: GetSex() { return (m_nSex = = 0?’m’:’f’); } 类中的成员函数有时很简单,这样的函数最适合写成内联成员函数以提高程序的执行效率
第7单元类和对象(I) 135 对于成员函数来说,除了可以采用关键词 inline将其声明为内联函数外,还有一种更简单的方 法,就是在类的声明中直接定义成员函数的函数体,这样的函数自动成为内联成员函数。例如, 可将类 Person的成员函数声明为内联成员函数: class person char m strName [20] t int mm sex public void ister(const char sname int age, char sex) i strcpy(m strName, name) m nAge age m nSex =(sex =='m?0: 1) void Get Name(char * name i strcpy (name, m strName) GetAge o I return m nA, char Getsex I return (m nSex ==0?'m:'f") 类的成员函数与普通函数一样,可以重载,也可以带有缺省参数。 723公有成员和私有成员 为了实现既要隐藏数据,又要为外界使用数据提供接口的封装目的,通常是将类中的数据 成员声明为私有的而将成员函数声明为公有的。然而,在设计一个具体类时,各成员的访问权 限还应根据实际需要而定。一般说来,将类中的数据成员声明成公有的将难以保证该成员的安 全性,而将类的中成员函数声明成私有时还是非常必要的。例如,类中的一个只供其成员函数 调用的成员函数就应当声明为私有的 习惯上将具有全局作用域的类声明放在一个头文件中,将成员函数的定义放在一个另一个 源程序文件中,以提高编程的灵活性。 724对象 对象是类的实例。从技术上讲,一个对象就是一个具有某种类类型的变量。与普通变量 样,对象也必须先经声明才可以使用。声明一个对象的一般形式为
第 7 单元 类和对象(I) - 135 - 对于成员函数来说,除了可以采用关键词 inline 将其声明为内联函数外,还有一种更简单的方 法,就是在类的声明中直接定义成员函数的函数体,这样的函数自动成为内联成员函数。例如, 可将类 Person 的成员函数声明为内联成员函数: class Person { private: char m_strName[20]; int m_nAge; int m_nSex; public: void Register(const char *name, int age, char sex) { strcpy(m_strName,name); m_nAge = age; m_nSex = (sex = = ‘m’?0:1); } void GetName(char *name) { strcpy(name, m_strName); } int GetAge() { return m_nAge; } char GetSex() { return (m_nSex = = 0?’m’:’f’); } }; 类的成员函数与普通函数一样,可以重载,也可以带有缺省参数。 7.2.3 公有成员和私有成员 为了实现既要隐藏数据,又要为外界使用数据提供接口的封装目的,通常是将类中的数据 成员声明为私有的而将成员函数声明为公有的。然而,在设计一个具体类时,各成员的访问权 限还应根据实际需要而定。一般说来,将类中的数据成员声明成公有的将难以保证该成员的安 全性,而将类的中成员函数声明成私有时还是非常必要的。例如,类中的一个只供其成员函数 调用的成员函数就应当声明为私有的。 习惯上将具有全局作用域的类声明放在一个头文件中,将成员函数的定义放在一个另一个 源程序文件中,以提高编程的灵活性。 7.2.4 对象 对象是类的实例。从技术上讲,一个对象就是一个具有某种类类型的变量。与普通变量一 样,对象也必须先经声明才可以使用。声明一个对象的一般形式为: