欢迎来到天天文库
浏览记录
ID:65574110
大小:411.00 KB
页数:73页
时间:2024-08-29
《C++程序设计-北京林业大学7%-第07章 继承和派生》由会员上传分享,免费在线阅读,更多相关内容在行业资料-天天文库。
第七章继承和派生 本章主要内容(1)理解继承的概念和意义。(2)理解单一继承、多重继承中基类与派生类之间的关系。(3)理解并掌握派生类构造函数的编写要求以及派生类对象的构造过程和机理。(4)掌握虚函数和多态性的概念。(5)掌握虚函数的定义方法、调用方法及其在实现多态性方面所起到的作用。(6)了解纯虚函数与抽象基类的概念。2北京林业大学软件教研室 7.1继承和派生的概念继承(Inheritance)就是在一个已存在的类的基础上建立一个新类,实质就是利用已有的数据类型定义出新的数据类型。在继承关系中:被继承的类称为基类(Baseclass)(或父类)定义出来的新类称为派生类(Derivedclass)(子类)3北京林业大学软件教研室 派生类不仅可以继承原来类的成员,还可以通过以下方式扩充新的成员:(1)增加新的数据成员(2)增加新的成员函数(3)重新定义已有成员函数(4)改变现有成员的属性4北京林业大学软件教研室 多层次继承:在派生过程中,派生出来的新类同样可以作为基类再继续派生出更新的类,依此类推形成一个层次结构。直接参与派生出某类称为直接基类;而基类的基类,以及更深层的基类称为间接基类。在类的层次结构中,处于高层的类表示最一般的特征,而处于底层的类则表示更具体的特征。类族:同时一个基类可以直接派生出多个派生类。这样形成了一个相互关联的类族。如,MFC就是这样的类族,它由一个CObject类派生出200个MFC类中的绝大多数。5北京林业大学软件教研室 基类1基类2……基类n派生类1派生类2多重继承单继承:派生类只有一个直接基类。多重继承:派生类同时有多个直接基类。基类派生类1派生类2单继承6北京林业大学软件教研室 7.2单继承7.2.1单继承的定义方式class派生类名:访问方式基类名{派生类中的新成员}7北京林业大学软件教研室 【例7-1】类Build_1是一个关于楼房数据的类。它的数据成员有posi_x、posi_y和area,分别表示楼房位置的经、纬度和建筑面积。它的成员函数只有set1,用于设置数据成员posi_x、posi_y和area的值。让Build_1作为基类,再增加数据成员height、成员函数set2和show来定义派生类Build_2。8北京林业大学软件教研室 7.2.2派生类的成员构成派生新类经历了三个步骤:(1)吸收基类成员派生类继承和吸收了基类的全部数据成员和除了构造函数、析构函数之外的全部成员函数。(2)改造基类成员一是基类成员的访问方式问题;二是对基类数据成员或成员函数的覆盖。(3)添加新成员保证了派生类在功能上比基类有所发展。9北京林业大学软件教研室 7.2.3继承方式对基类成员的访问属性控制1.公有继承(public继承方式)基类中public和protected成员的访问属性在派生类中不变;而基类中的不可访问成员和private成员在派生类中不可访问。注意:不可访问成员与私有成员的区别。10北京林业大学软件教研室 2.私有继承(private继承方式)基类中public和protected成员都以private成员出现在派生类中;而基类中的不可访问成员和private成员在派生类中不可访问。相当于中止了基类功能的继续派生!11北京林业大学软件教研室 3.保护继承(protected继承方式)基类中public和protected成员都以protected成员出现在派生类中;而基类中的不可访问成员和private成员在派生类中不可访问。12北京林业大学软件教研室 类的继承方式对基类成员的访问属性控制基类成员作为派生类成员公有继承保护继承私有继承public成员public成员protected成员private成员protected成员protected成员protected成员private成员private成员不可访问不可访问不可访问不可访问成员不可访问不可访问不可访问13北京林业大学软件教研室 【例7-2】验证公有继承方式下,类成员的访问特性。14北京林业大学软件教研室 【例7-3】验证私有继承方式下,类成员的访问特性。15北京林业大学软件教研室 【例7-4】验证保护继承方式下,类成员的访问特性。16北京林业大学软件教研室 7.2.4派生类的构造函数派生类的构造函数:一方面负责调用基类的构造函数对基类成员进行初始化;另一方面还要负责对基类的构造函数所需要的参数进行必要的设置。派生类名::派生类构造函数名(总参数列表):基类构造函数名(参数列表){派生类中新增数据成员初始化语句}17北京林业大学软件教研室 在定义派生类的对象时:系统首先执行基类的构造函数;然后执行派生类的构造函数。【例7-5】定义一个点类Point,并由此派生出一个圆类Circle,并测试派生类的构造函数和基类的构造函数的执行顺序。18北京林业大学软件教研室 派生类对基类成员重新定义:通过派生类的对象调用一个被重新定义过的基类的成员函数,被调用的是派生类的成员函数;此时,若想调用基类的同名成员函数,必须在成员函数名前加基类名和作用域运算符“::”。【例7-6】本例中分别定义一个描述圆的类Ccircle和一个描述圆柱体的类Ccylinder。19北京林业大学软件教研室 在C++中,处理同名函数时有以下3种基本方法:①根据函数参数的特征进行区分,即编译器根据参数的类型或个数进行区分。如:max(int,int)max(float,float)②根据类对象进行区分。如:在上例中的main函数中,cylinder.area()circle.area()③使用作用域运算符“::”进行区分,如:Ccircle::area()以上3种方法都是在程序编译过程中完成的,因此称为静态联编。20北京林业大学软件教研室 7.2.5有子对象的派生类的构造函数派生类名::派生类构造函数名(总参数列表):基类构造函数名(参数列表),子对象名(参数列表),……{派生类中新增数据成员初始化语句}此时,构造函数执行的一般次序为:①调用基类的构造函数。②调用子对象的构造函数。当派生类中含有多个子对象时,各子对象的构造函数的调用顺序按照它们在类中说明的先后顺序进行。③执行派生类构造函数的函数体。21北京林业大学软件教研室 7.2.6派生类的析构函数析构函数的作用是在对象撤销之前,进行必要的清理工作。当对象被删除时,系统会自动调用析构函数。析构函数的调用顺序与构造函数的调用顺序正好相反:先执行派生类自己的析构函数;然后调用子对象的析构函数;最后调用基类的析构函数。【例7-7】分析以下程序的执行结果。22北京林业大学软件教研室 练习类有两种用法:一种是类的实例化,即生成类的对象;另一种是通过___________,派生出新的类。如果类A继承了类B,则类A称为___________,类B称为___________。23北京林业大学软件教研室 判断题在派生类的构造函数的初始化表中不能包含对基类的子对象的初始化。一个派生类还可以作为另一个类的派生类。派生类至少有一个基类。派生类中继承的基类的成员的访问权限到派生类保持不变。派生类的对象可以对它的基类成员中公有继承的保护成员进行访问。派生类的构造函数的执行顺序是:对象成员的构造函数、基类的构造函数、派生类本身的构造函数。基类的私有成员不能为派生类的成员所访问。基类的公有成员在私有继承时在派生类中成为私有成员,而在保护继承时在派生类中成为保护成员。在公有和保护继承方式下,派生类的成员可以对基类的保护成员进行访问。在公有和保护继承方式下,派生类的对象可以对基类的保护成员进行访问。24北京林业大学软件教研室 读程序#includeclassBase{public:Base(){cout<<"执行基类构造函数"<classA{public:A(char*s){cout<classA{public:A(char*s){cout<#includeclassPerson{public:Person(char*n){name=newchar[strlen(n)+1];strcpy(name,n);}voidprint(){cout<<"Mynameis"<print();Studenty("zhang",97);p=&y;p->print();Professorz("liu","computer");p=&z;p->print();}程序运行结果为:Mynameiswang.Mynameiszhang.Mynameisliu.程序运行结果为:Mynameiswang.Mynameiszhangandmyscoreis97.Mynameisliuandmycourseiscomputer.将Person类中的voidprint()virtualvoidprint()50北京林业大学软件教研室 7.4.4虚函数class类名{virtual类型函数名(参数表);};说明:(1)虚函数声明只能出现在类声明中的函数原型声明中,而不能在成员函数的函数体实现的时候。(2)只有类的普通成员函数才能声明为虚函数,全局函数及静态成员函数不能声明为虚函数。51北京林业大学软件教研室 (3)虚函数可以在一个或多个派生类中被重新定义,因此,它属于函数重载的情况。它要求在派生类中重新定义时必须与基类中的函数原型完全相同。这时,无论在派生类的相应成员函数前是否加上关键字virtual,都将其视为虚函数;系统会遵循以下规则来判断一个派生类的成员函数是不是虚函数:①该函数是否与基类的虚函数有相同的名称;②该函数是否与基类的虚函数有相同的参数个数及相同的对应参数类型;③该函数是否与基类的虚函数有相同的返回值或者满足赋值兼容规则的指针、引用型的返回值。52北京林业大学软件教研室 (4)当一个类的成员函数声明为虚函数后,就可以在该类的(直接或间接)派生类中定义与其基类虚函数原型相同的函数。这时,当用基类指针指向这些派生类对象时,系统会自动用派生类中的同名函数来代替基类中的虚函数。也就是说,当用基类指针指向不同派生类对象时,系统会在程序运行中根据所指向对象的不同,自动选择适当的成员函数,从而实现了运行时的多态性。【例7-13】虚函数的定义与应用举例。53北京林业大学软件教研室 运行过程中的多态需要满足三个条件:首先类之间应满足赋值兼容规则;其次是要声明虚函数;第三是要由成员函数来调用或者通过指针、引用来访问虚函数。如果使用对象名来访问虚函数,由于联编在编译过程中就可以进行(静态联编),而无需在运行过程中进行。54北京林业大学软件教研室 读程序#includeclassbase{private:intb;public:base(intx=0){b=x;}virtualvoidshow(){cout<<"base::b="<classBase{public:virtualvoidfun(intx){cout<<"baseclass,x="<classCAnimal{public:CAnimal();};//Animal.cpp#include"Animal.h"CAnimal::CAnimal(){cout<<"Animal!"<classCAnimal{public:CAnimal();};#endif66北京林业大学软件教研室 【例7-16】设计一个基类Person,包含name和age两个数据成员;由它派生出学生类Student和教师类Teacher,其中学生类添加学号no数据,教师类添加职称title数据;每个类均有构造函数和析构函数;编程实现,并用一些数据进行测试。PersonTeacherStudent(1)派生类的有参构造函数中需要为基类的有参构造函数提供参数。(2)由于在派生类中重新定义了显示函数,若要调用基类的显示函数,则需要使用Person::show()的形式。67北京林业大学软件教研室 【例7-17】设计一个抽象类Vehicle,其中包含2个纯虚函数setdata()和show();由它派生出类Car和类Truck,类Car包含名称、颜色、载客数3个数据成员,类Truck包含名称、颜色、载重量3个数据成员。68北京林业大学软件教研室 小结(1)在C++中,允许以某个类为基类并用继承的方式定义新的类,继承性是C++的一个重要机制;C++支持单继承和多重继承,这样便形成了类的层次结构,处在最高层的类具有一般特征,而越处在底层的类就越详细、越具体。69北京林业大学软件教研室 小结(2)派生新类需要经历三个步骤:吸收基类成员、改造基类成员和添加新成员。派生类继承和吸收了基类的全部数据成员和除了构造函数、析构函数之外的全部成员函数;对基类成员的改造包括两个方面:一是基类成员的访问方式问题,这由派生类定义时的访问方式来控制;二是对基类数据成员或成员函数的覆盖,对基类的功能进行改造;派生类中新成员的加入是保证派生类在功能上有所发展的关键。70北京林业大学软件教研室 小结(3)在多继承关系中,被继承的多个基类中如果有具有同名的成员时,则在派生类中对该同名成员的使用会产生二义性,即编译系统将无法知道是使用的哪个基类中的成员。为了解决该问题,我们可以采用作用域运算符和虚基类两种方法来实现。71北京林业大学软件教研室 小结(4)赋值兼容规则是指在公有继承的情况下,对于某些场合,一个派生类的对象可以作为基类对象来使用,也就是在需要基类对象的任何地方都可以使用公有派生类的对象来替代。它包括三种情况:派生类的对象可以赋值给基类对象;派生类的对象可以初始化为基类的引用;派生类对象的地址可以赋给指向基类的指针。72北京林业大学软件教研室 小结(5)C++的多态性是通过虚函数实现的,在继承环境下通过虚函数达到动态联编的效果,从而实现了程序运行时的多态性。73北京林业大学软件教研室
此文档下载收益归作者所有
举报原因
联系方式
详细说明
内容无法转码请点击此处