《七章类与对象》由会员分享,可在线阅读,更多相关《七章类与对象(57页珍藏版)》请在金锄头文库上搜索。
1、1第七章第七章 类与对象类与对象2教学目标l(1) 理解以类与对象为核心的面向对象程序设计的基本思想,包括封理解以类与对象为核心的面向对象程序设计的基本思想,包括封装、继承和多态性的概念及其在面向对象程序中的体现;装、继承和多态性的概念及其在面向对象程序中的体现;l(2) 掌握类的定义方法;掌握类的定义方法;l(3) 掌握类成员的访问权限控制;掌握类成员的访问权限控制;l(4) 掌握对象的创建与使用方法;掌握对象的创建与使用方法;l(5) 了解构造函数与析构函数的定义与使用。了解构造函数与析构函数的定义与使用。l(6) 了解类的继承与派生、运算符重载、以及模板等概念。了解类的继承与派生、运算符
2、重载、以及模板等概念。3基本内容 l7.1 面向对象程序设计概述面向对象程序设计概述l7.2 类与对象类与对象l7.3 继承继承47.1 面向对象程序设计概述l两种程序设计思想两种程序设计思想: :l面向过程的程序设计面向过程的程序设计( (Structure ProgrammingStructure Programming) )l以功能为中心,采用函数来描述操作以功能为中心,采用函数来描述操作( (动词动词) )l面向对象程序设计面向对象程序设计( (Object Oriented ProgrammingObject Oriented Programming) )l以数据为中心,采用对象来描
3、述内部属性和操作方法以数据为中心,采用对象来描述内部属性和操作方法( (名词名词) )5对象和面向对象l客观世界客观世界实体实体l例:人类例:人类l静态特征(属性静态特征(属性attributeattribute)l姓名、性别、年龄、班级(姓名、性别、年龄、班级(/ /单位)、身高等单位)、身高等l动态特征(行为动态特征(行为behaviorbehavior) l吃饭、睡觉、说话、走路、上课(吃饭、睡觉、说话、走路、上课(/ /上班)等上班)等l例:汽车例:汽车l静态特征(属性静态特征(属性attributeattribute)l品牌、生产厂、型号、颜色等品牌、生产厂、型号、颜色等l动态特征(
4、行为动态特征(行为behaviorbehavior) l行驶、转弯、鸣笛、刹车等行驶、转弯、鸣笛、刹车等6面向对象的基本特征l抽象抽象:数据抽象数据抽象+ +代码抽象代码抽象l封装封装:过程和数据封藏起来过程和数据封藏起来l继承继承:基类和派生类基类和派生类l多态性多态性:虚函数、函数重载虚函数、函数重载7OOP的优点l开发时间短,效率高,可靠性高,所开发开发时间短,效率高,可靠性高,所开发的程序更强壮的程序更强壮重用,共享,可维护性,精简重用,共享,可维护性,精简l适合于大程序长时间的开发工作适合于大程序长时间的开发工作87.2 类与对象l7.2.1 类的定义类的定义l7.2.2 成员函数成
5、员函数l7.2.3 对象的使用对象的使用l7.2.4 构造函数与析构函数构造函数与析构函数9类(Class) -数据类型l类是具有相同属性和相同的方法的对象的集合,类是具有相同属性和相同的方法的对象的集合,它是一种既包含数据又包含函数的抽象数据类它是一种既包含数据又包含函数的抽象数据类型。型。l类的构成类的构成l数据成员(数据成员(Data MemberData Member),即类的属性;),即类的属性;l成员函数(成员函数(Member FunctionMember Function),即类的方法;),即类的方法;107.2.1 类的定义 class 类名类名 private:/私有成员私
6、有成员 私有的数据成员和成员函数;私有的数据成员和成员函数;protected:/保护成员保护成员 保护的数据成员和成员函数;保护的数据成员和成员函数;public:/公有成员公有成员 公有的数据成员和成员函数;公有的数据成员和成员函数;;11访问控制权限 l私有部分(私有部分(private):数据成员和成员函数只):数据成员和成员函数只能在该类的范围内被本类的成员函数访问能在该类的范围内被本类的成员函数访问体现类的封装性体现类的封装性 l保护部分(保护部分(protected):与私有成员的性质相):与私有成员的性质相似似l公有部分(公有部分(public):成员既可以被本类的成):成员既
7、可以被本类的成员函数访问,也在类外被该类的对象访问员函数访问,也在类外被该类的对象访问对外界的接口对外界的接口 12例:定义一个狗类(Dog)class Dogprivate:char name20;/ 狗的名字狗的名字intage;/ 狗的年龄狗的年龄public:voidset(char *n, int a);/ 设置数据成员值的函数设置数据成员值的函数voiddisplay();/ 输出数据成员值的函数输出数据成员值的函数voidspeak();/ 发出狗叫声的函数发出狗叫声的函数;137.2.2 成员函数l成员函数的一般形式:成员函数的一般形式:函数类型函数类型 类名类名 : 函数名函
8、数名 ( 参数表参数表 )函数体函数体14类的作用域 l一个类的所有数据成员和成员函数都在该类的作用域内一个类的所有数据成员和成员函数都在该类的作用域内(包括在类声明外部定义的成员函数)(包括在类声明外部定义的成员函数)l类中的每个成员都可以直接访问本类中的其他任何成员。类中的每个成员都可以直接访问本类中的其他任何成员。l如果在类作用域之外对该类的数据成员和成员函数进行如果在类作用域之外对该类的数据成员和成员函数进行访问,则要受到一定的限制,有时甚至是不允许的。访问,则要受到一定的限制,有时甚至是不允许的。15例:Dog类成员函数的定义void Dog:set(char *n, int a)s
9、trcpy(name,n);age = a;void Dog:display()coutnametageendl;void Dog: speak()coutArf!Arf!endl;16/ Dog类较完整的定义类较完整的定义class Dog private:char name20;intage;public:voidset(char *n, int a);voiddisplay();voidspeak();void Dog:set(char *n, int a)strcpy(name,n);age = a;void Dog:display()coutnametageendl;void Dog
10、: speak()coutArf!Arf!endl;17/ 当成员函数比较简单时,可在类定义中直接给出函数体当成员函数比较简单时,可在类定义中直接给出函数体class Dog private:char name20;intage;public:voidset(char *n, int a)strcpy(name,n);age = a;voiddisplay()coutnametageendl;voidspeak()coutArf!Arf!- 运算符运算符19例7-1: Dog类和对象int main()char name020;int age0;Dog dog1, dog2;cout name
11、0 age0;dog1.set (name0, age0);cout 第一条狗:第一条狗: endl;dog1.display();dog1.speak();dog2.set (LaiFu, 2);cout 第二条狗:第二条狗: endl;dog2.display ();dog2.speak();dog1=dog2;/ 同类对象之间可以互相赋值同类对象之间可以互相赋值cout 对象赋值后的第一条狗:对象赋值后的第一条狗: endl;dog1.display();dog1.speak();return 0;20对象的使用成员函数可直接访问本类中定义的数据成员成员函数可直接访问本类中定义的数据成员
12、(公(公有和私有)有和私有)类的作用域内类的作用域内类的对象访问其类的对象访问其公有公有数据成员或成员函数需使用数据成员或成员函数需使用运算符运算符“”禁止直接访问一个对象中的禁止直接访问一个对象中的私有私有/ /保护保护成员成员同类对象之间可以整体赋值同类对象之间可以整体赋值对象用作函数的参数时属于赋值调用;函数可以对象用作函数的参数时属于赋值调用;函数可以返回一个对象。返回一个对象。 217.2.4 构造函数与析构函数l构造函数(构造函数(ConstructorConstructor)是类的一个特殊成员是类的一个特殊成员函数,函数,定义了创建对象的方法,提供了初始化定义了创建对象的方法,提
13、供了初始化对象的一种简便手段。对象的一种简便手段。l与构造函数相对应,析构函数(与构造函数相对应,析构函数(DestructorDestructor)用于撤消一个对象用于撤消一个对象,完成释放对象成员所占存,完成释放对象成员所占存储空间的工作。储空间的工作。 22构造函数(构造函数(Constructor)l格式:格式:类名类名 : : 类名类名 ( (参数表参数表) ) 函数体函数体 l注意事项:注意事项:l构造函数必须与类名相同构造函数必须与类名相同l构造函数没有返回值构造函数没有返回值l其其功功能能是是对对对对象象进进行行初初始始化化,一一般般由由一一系系列列赋赋值值语语句句构成构成l由
14、系统自动调用由系统自动调用23析构函数(析构函数(Destructor)l格式为:格式为:类名类名:类名类名();l注意事项:注意事项:l函数名与类名相同,只是在前边加函数名与类名相同,只是在前边加“”符号符号l析构函数不得返回任何值析构函数不得返回任何值l析构函数不得带有任何参数析构函数不得带有任何参数l其功能是释放对象成员所占用的存储,一般由一系其功能是释放对象成员所占用的存储,一般由一系列的列的delete组成组成l由系统自动调用由系统自动调用24例7-2: 使用构造函数和析构函数的Dog类class Dog char name20;intage;public:Dog()/ 构造函数构造
15、函数1strcpy(name, XXX);age = 0;Dog(char *n, int a)/ 构造函数构造函数2strcpy(name, n);age = a;Dog()/ 析构函数析构函数cout析构函数被调用析构函数被调用endl;voiddisplay() coutnametageendl;voidspeak() coutArf!Arf!endl;257.3 继承l7.3.1 派生类的定义派生类的定义l7.3.2 派生类的继承方式和访问属性派生类的继承方式和访问属性l7.3.3 派生类的构造函数和析构函数派生类的构造函数和析构函数26生物类的层次关系277.3.1 派生类的定义l派
16、生类的定义格式为:派生类的定义格式为:class 派派生生类类名名:继继承承方方式式 基基类类名名1,继继承承方方式式 基基类名类名2,继承方式继承方式 基类名基类名n派生类增加的成员声明;派生类增加的成员声明;; 28/人员类定义人员类定义class Personprotected:char Name10; /姓名姓名char Sex;/性别性别public:void ShowMe() /显示数据成员显示数据成员cout Namet Sexn;/雇员类定义雇员类定义class Employee : public Person char Dept20;/工作部门工作部门public:void
17、ShowMe() /显示数据成员显示数据成员cout Namet Sext Dept n;单继承的例子单继承的例子 29/飞机类飞机类 class Planechar propeller; /螺旋桨螺旋桨public:void flying();/飞行方法飞行方法;/船类船类class Boatchar helm;/舵舵public:void floating();/飘浮方法飘浮方法;/水上飞机类水上飞机类 class Seaplane : public Plane, public Boat;多继承的例子多继承的例子 307.3.2 派生类的继承方式和访问属性l私有继承私有继承privatel
18、公有继承公有继承publicl保护继承保护继承protected31派生类的定义格式class 派生类名:派生类名:private | protected | public 基类名基类名private:protected:public:;系统的默认值是私有继承系统的默认值是私有继承32公有继承(public)l以公有继承方式创建的派生类对基类各种成员访问权限以公有继承方式创建的派生类对基类各种成员访问权限如下如下 :l基类公有成员相当于派生类的公有成员,即派生类可以象访问自基类公有成员相当于派生类的公有成员,即派生类可以象访问自身公有成员一样访问从基类继承的公有成员。身公有成员一样访问从基类继
19、承的公有成员。 l基类保护成员相当于派生类的保护成员,即派生类可以象访问自基类保护成员相当于派生类的保护成员,即派生类可以象访问自身的保护成员一样,访问基类的保护成员。身的保护成员一样,访问基类的保护成员。 l对于基类的私有成员,派生类无法直接访问。对于基类的私有成员,派生类无法直接访问。33私有继承 (private)l派生类对基类各种成员访问权限如下派生类对基类各种成员访问权限如下 :l基类公有成员和保护成员都相当于派生类的私有成员,派生类基类公有成员和保护成员都相当于派生类的私有成员,派生类只能通过自身的函数成员访问它们;只能通过自身的函数成员访问它们; l对于基类的私有成员,无论派生类
20、内部成员或派生类使用者都对于基类的私有成员,无论派生类内部成员或派生类使用者都无法直接访问。无法直接访问。 34保护继承(protected)l派生类对基类各种成员访问权限如下派生类对基类各种成员访问权限如下 :l基类的公有成员和保护成员都相当于派生类的保护成员,派生类可基类的公有成员和保护成员都相当于派生类的保护成员,派生类可以通过自身的成员函数或其子类的成员函数访问它们以通过自身的成员函数或其子类的成员函数访问它们l对于基类的私有成员,无论派生类内部成员或派生类使用者都无法对于基类的私有成员,无论派生类内部成员或派生类使用者都无法直接访问直接访问 35基类成员在派生类中的访问属性基类中的成
21、员基类中的成员在派生类中的访问属性在派生类中的访问属性公有派生公有派生私有派生私有派生保护派生保护派生公有成员公有成员公有公有私有私有保护保护私有成员私有成员不可访问不可访问不可访问不可访问不可访问不可访问保护成员保护成员保护保护私有私有保护保护36/ 例例7-3:派生类的定义及使用:派生类的定义及使用#include #include using namespace std;class Person/人员类定义人员类定义char Name10;/姓名姓名intAge;/年龄年龄public:void Set(char *name, int age)/设置数据成员设置数据成员strcpy(Na
22、me, name);Age = age;void Display()coutNametAgetendl; ;class Student : public Person/学生类定义(公有继承)学生类定义(公有继承)int Number;/ 学号学号char ClassName10;/ 班级班级public:voidSetStu(char *classname, int number, char *name, int age) strcpy(ClassName, classname); Number = number;Set(name, age); /派生类成员函数直接使用基类的公有成员派生类成员
23、函数直接使用基类的公有成员voidDisplayStu()cout Number t ClassName t; Display();/派生类成员函数直接使用基类的公有成员派生类成员函数直接使用基类的公有成员;int main()Student stu1;stu1.SetStu(计算机计算机21, 95071007, 张三张三, 19);stu1.Display();/派生类对象直接使用基类的公有成员派生类对象直接使用基类的公有成员stu1.DisplayStu();return 0;377.3.3 派生类的构造函数和析构函数l派生类构造函数的一般形式为:派生类构造函数的一般形式为:派生类名派生
24、类名:派生类名(参数总表)派生类名(参数总表):基类名基类名1(参数表(参数表1),),基类名,基类名n(参数表参数表n),),内嵌对象名内嵌对象名1(对象参数表(对象参数表1),),内嵌对象名,内嵌对象名m(对象参数表对象参数表m)派生类新增加成员的初始化;派生类新增加成员的初始化;38派生类构造函数的执行次序l首先,调用基类构造函数,调用顺序按照它们被继承时首先,调用基类构造函数,调用顺序按照它们被继承时声明的基类名顺序执行。声明的基类名顺序执行。l其次,调用内嵌对象构造函数,调用次序按各个对象在其次,调用内嵌对象构造函数,调用次序按各个对象在派生类内声明的顺序。派生类内声明的顺序。l最后
25、,执行派生类构造函数体中的内容。最后,执行派生类构造函数体中的内容。 39析构函数 l派生类与基类的析构函数没有什么联系,彼此独立,派派生类与基类的析构函数没有什么联系,彼此独立,派生类或基类的析构函数只作各自类对象消亡前的善后工生类或基类的析构函数只作各自类对象消亡前的善后工作。作。l派生类析构函数执行过程恰与构造函数执行过程相反。派生类析构函数执行过程恰与构造函数执行过程相反。l首先执行派生类析构函数首先执行派生类析构函数l然后执行内嵌对象的析构函数然后执行内嵌对象的析构函数l最后执行基类析构函数最后执行基类析构函数 40/ 例例7-4:派生类构造函数和析构函数:派生类构造函数和析构函数#
26、include #include using namespace std;class Person/人员类定义人员类定义char Name10;intAge;public:Person(char* name,int age)/构造函数构造函数strcpy(Name, name);Age = age;coutPerson类的构造函数被调用类的构造函数被调用endl; Person()/析构函数析构函数coutPerson类的析构函数被调用类的析构函数被调用endl;void Display() coutNametAgetendl; ;class Student : public Person/学
27、生类定义(公有继承)学生类定义(公有继承)int Number;char ClassName10;public:Student(char *classname, int number, char *name, int age) : Person(name, age) strcpy(ClassName, classname);Number = number;coutStudent类的构造函数被调用类的构造函数被调用 endl;Student() coutStudent类的析构函数被调用类的析构函数被调用endl; voidDisplayStu()cout Number t ClassName ”
28、和和“”用作输入输出运算符用作输入输出运算符 7.4.1 运算符重载运算符重载 45运算符重载的定义l形式:形式:函数返回值函数返回值类型类型 类名类名: operator 运算符运算符 (参数表参数表)l运算符重载实际也是一种函数重载运算符重载实际也是一种函数重载l函数 operator 运算符重载了运算符46/例例7-5: 重载复数类的运算符重载复数类的运算符class Complexdouble real, imag;public:Complex(double r = 0, double i = 0) / 带默认参数值的构造函数带默认参数值的构造函数real=r; imag=i;doub
29、le Real() return real;/ 取复数的实部取复数的实部double Imag() return imag;/ 取复数的虚部取复数的虚部Complex operator +(Complex &);/ 重载运算符重载运算符 Complex operator -(Complex &);/ 重载运算符重载运算符 ;Complex Complex:operator + (Complex &c)Complex temp;temp.real = real+c.real;temp.imag = imag+c.imag;return temp;Complex Complex:operator
30、- (Complex &c)Complex temp;temp.real = real-c.real;temp.imag = imag-c.imag;return temp;477.4.2 虚函数虚函数 l定义:定义:在某在某基类基类中声明为中声明为virtual并在一个或多个派生并在一个或多个派生类中被重新定义的成员函数类中被重新定义的成员函数 l语法:语法:virtual 函数返回类型函数返回类型 函数名(参数表)函数名(参数表) 函数体函数体l用途:用途:实现多态性,通过指向派生类的基类指针,访实现多态性,通过指向派生类的基类指针,访问派生类中同名覆盖成员函数问派生类中同名覆盖成员函数4
31、8例 7-6: 使用虚函数实现多态性#include using namespace std;class Animal /基类:动物类基类:动物类public:virtual void Speak() coutHow does a Animal speak?endl; ;class Cat : public Animal /派生类:猫类派生类:猫类public:virtual void Speak() coutmiao!miao!endl; ; class Dog : public Animal/派生类:狗类派生类:狗类public:virtual void Speak() coutwang!
32、wang!endl; ;49虚函数的使用限制 l应通过应通过指针或引用指针或引用调用虚函数,而不要以对象名调用调用虚函数,而不要以对象名调用虚函数虚函数说明语句;说明语句;l在派生类中重定义的基类虚函数仍为虚函数,同时可在派生类中重定义的基类虚函数仍为虚函数,同时可以省略以省略virtual关键字;关键字; l在派生类重新定义时,必须与基类中的原型完全相同;在派生类重新定义时,必须与基类中的原型完全相同;否则会成为一般的重载;否则会成为一般的重载;l不能定义虚构造函数,可以定义虚析构函数。不能定义虚构造函数,可以定义虚析构函数。 50抽象类 l纯虚函数纯虚函数 virtual 返回类型返回类型
33、 函数名(参数表)函数名(参数表)=0 l具体实现只能在派生类中完成具体实现只能在派生类中完成l抽象类抽象类l至少包含一个纯虚函数的类至少包含一个纯虚函数的类l抽象类为其所有子类提供了统一的操作界面,使其抽象类为其所有子类提供了统一的操作界面,使其派生类具有一系列统一的方法。派生类具有一系列统一的方法。51抽象类的使用要求 l抽象类不能实例化抽象类不能实例化 l抽象类只作为基类被继承抽象类只作为基类被继承 l可以定义指向抽象类的指针或引用可以定义指向抽象类的指针或引用,这个指针,这个指针或引用必然指向派生类对象。从而实现多态性。或引用必然指向派生类对象。从而实现多态性。 527.5 类模板l与
34、函数模板相似,程序中可以通过高度抽象首与函数模板相似,程序中可以通过高度抽象首先定义一个类模板,然后通过使用不同的实参先定义一个类模板,然后通过使用不同的实参生成不同的类。生成不同的类。l类是对问题空间的抽象,而类模板则是对类的类是对问题空间的抽象,而类模板则是对类的抽象,即更高层次上的抽象。抽象,即更高层次上的抽象。l类模板的定义方法为:类模板的定义方法为:template class 类名;53/ 例例7-7 类模板的使用类模板的使用#include using namespace std;template class AnyTypeTx;public:AnyType(T a)x=a;T
35、GetX()return x;int main()AnyType i (5);AnyType d (3.14);AnyType c (a);cout 整型类:整型类: i.GetX() endl;cout 双精度类:双精度类: d.GetX() endl;cout 字符类:字符类: c.GetX() endl;return 0; 54上机指导l7.6 使用使用ClassView标签标签55应用举例l例例7-8设计一个时间类,要求能够设置设计一个时间类,要求能够设置时间、进行时间的加减运算,并以一定时间、进行时间的加减运算,并以一定格式显示时间。格式显示时间。l例例7-9编写教师信息管理程序,实现显编写教师信息管理程序,实现显示教师信息、增加教师信息、删除教师示教师信息、增加教师信息、删除教师信息等功能。信息等功能。56学好程序设计语言的唯一途径是学好程序设计语言的唯一途径是 你的编程能力与你在计算机上投入的时间成你的编程能力与你在计算机上投入的时间成 结结 束束 语语57