《【精品】c c++语言程序设计(西电版第11章 派生类与继承(可编辑.ppt》由会员分享,可在线阅读,更多相关《【精品】c c++语言程序设计(西电版第11章 派生类与继承(可编辑.ppt(46页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、C C+语言程序设计(西电版)第11章 派生类与继承第十一章第十一章 派生派生类类与与继继承承11.1类的的继承与派生承与派生11.2 派生派生类的构造函数和析构函数的构造函数和析构函数11.3 多重多重继承承11.4 虚基虚基类11.5 小小结 继承承是是C+的一种重要机制,是程序可重的一种重要机制,是程序可重用与用与扩充的一个重要方面。充的一个重要方面。这一机制使得一机制使得程序程序员可以在已有可以在已有类的基的基础上建立新上建立新类。从而从而扩展程序功能、体展程序功能、体现类的多的多态性特征。性特征。11.1 类的的继承与派生承与派生l自然世界的自然世界的类概念是概念是抽象的抽象的,类的
2、下面的下面还有子有子类,子,子类继承父承父类的各种特征。的各种特征。l面向面向对象程序象程序设计允允许你声明一个新你声明一个新类作作为另另一个一个类的派生。的派生。l派生派生类(也称子(也称子类)可以声明新的属性(成)可以声明新的属性(成员)和新的操作(成和新的操作(成员函数)。函数)。l继承承可以可以让你你重用重用父父类代代码,专注于注于为子子类编写新代写新代码。l我我们称最初的称最初的类为基基类,根据它生成的,根据它生成的类称称为派生派生类(子(子类),),这种派生可以是多种派生可以是多层次的。次的。11.1.1 继承与派生的概念承与派生的概念哺乳动物类哺乳动物类猫类猫类犬类犬类波斯猫波斯
3、猫安哥拉猫安哥拉猫西施犬西施犬沙皮犬沙皮犬基基类类class personprivate:char name10;int age;char sex;public:void print();派生派生类类class employee:public personprivate:char department20;float salary;public:/派生方式派生方式l公有派生公有派生class employee:public person /l私有派生私有派生class employee:private person /l保保护派生派生class employee:protected perso
4、n /特点:特点:l公有公有继承:承:基基类的公有成的公有成员和保和保护成成员作作为派生派生类的成的成员时,它,它们都保持原有的状都保持原有的状态,而基,而基类的的私有成私有成员仍然是私有的。仍然是私有的。l保保护继承:承:基基类的所有公有成的所有公有成员和保和保护成成员都成都成为派生派生类的保的保护成成员,并且只能被它的派生,并且只能被它的派生类成成员函数或友元函数或友元访问,基,基类的私有成的私有成员仍然是私有仍然是私有的。的。l私有私有继承:承:基基类的公有成的公有成员和保和保护成成员都作都作为派派生生类的私有成的私有成员,并且不能被,并且不能被这个派生个派生类的子的子类所所访问。l缺省
5、缺省继承方式承方式为private.继承方式基类特性派生类特性公有继承PublicprotectedprivatePublicProtected不可访问私有继承PublicprotectedprivatePrivatePrivate不可访问保护继承PublicprotectedprivateProtectedProtected不可访问例例11.1 派生派生类对基基类的的访问特性。特性。#include class Apublic:void f1();protected:int j1;private:int i1;class B:public Apublic:void fn2();protect
6、ed:int j2;private:int i2;class C:public B public:void f3();问题:1.B中成中成员函数函数f2()能否能否访问基基类中的成中的成员:f1(),i1,j1?2.B的的对象象b1能否能否访问的成的成员?3.的成的成员函数函数f3()能否能否访问直接基直接基类B中的中的成成员:f2(),i2,j2?4.派生派生类C的的对象象c1是否可以是否可以访问直接基直接基类B的成的成员?能否?能否访问间接其接其类A的成的成员:f1(),i1,j1?回答:回答:1.可以可以访问f1(),j1,不可不可访问i1;2.可以可以访问f1(),不可不可访问i1,j
7、1;3.可以可以访问f2(),j2,f1(),j1,不可不可访问i1,i2;4.可以可以访问f2(),f1(),其他的都不可以其他的都不可以访问;结论:在公有在公有继承承时,派生,派生类的成的成员函数可函数可访问基基类中的公有成中的公有成员和保和保护成成员;派生;派生类的的对象象仅可可访问基基类中的公有成中的公有成员。【例例11.2】私有派生私有派生类对基基类成成员的的访问。#include class base /声明一个基声明一个基类 int x;public:void setx(int n)x=n;void showx()coutxendl;class derived:private b
8、ase /声明一个私有派生声明一个私有派生类 int y;public:void sety(int n)y=n;void showxy()coutxyendl;/非法,派生非法,派生类不能不能访问基基类的私有成的私有成员;【例例 11.3】私有派生私有派生类对基基类成成员的的访问。#include class base int x;public:void setx(int n)x=n;void showx()coutxendl;class derived:private base int y;public:void sety(int n)y=n;void showy()coutyendl;ma
9、in()derived obj;obj.setx(10);/非法非法 obj.sety(20);/合法合法 obj.showx();/非法非法 obj.showy();/合法合法 return 0;l如果将如果将derived类改改为公有派生,公有派生,则main函数函数中的中的调用合法否?(例用合法否?(例11.4)l如果将如果将derived类改改为保保护派生,派生,则main函数函数中的中的调用合法否?(例用合法否?(例11.4)思考思考l在派生在派生类中声明的名字可以支配基中声明的名字可以支配基类中声中声明的同名的名字。如果在派生明的同名的名字。如果在派生类的成的成员函函数中直接使用数
10、中直接使用该名字的名字的话,则表示使用派表示使用派生生类中声明的名字,例如:中声明的名字,例如:class Xpublic:int f();class Y:public Xpublic:int f();int g();void Y:g()f();/表示被表示被调用的函数是用的函数是Y:f(),而不是,而不是X:f()11.2 派生派生类的构造函数和析构函数的构造函数和析构函数 基基类都有都有显示的或示的或隐式的构造函数和析式的构造函数和析构函数。当构函数。当创建一个派生建一个派生类对象象时,如何,如何调用基用基类的构造函数的构造函数对基基类数据初始化,以及数据初始化,以及在撤在撤销派生派生类对
11、象象时,又如何,又如何调用基用基类的析的析构函数构函数对基基类对象的数据成象的数据成员进行善后行善后处理,理,是本是本节所要所要讨论的内容。的内容。11.2.1构造和析构的次序构造和析构的次序l通常情况下,当通常情况下,当创建派生建派生类时,首先,首先执行行基基类的构造函数,随后再的构造函数,随后再执行派生行派生类的构的构造函数;当撤造函数;当撤销派生派生类对象象时,则先先执行行派生派生类的析构函数,随后再的析构函数,随后再执行基行基类的析的析构函数。构函数。l参参见例例11.6【例例11.6】掌握基掌握基类和派生和派生类的构造函数和析构函数的构造函数和析构函数的的执行行顺序。序。#inclu
12、de class basepublic:base()cout基基类的构造函数的构造函数endl;base()cout基基类的析构函数的析构函数endl;class derive:public basepublic:derive()cout派生派生类的构造函数的构造函数endl;derive()cout派生派生类类的析构函数的析构函数endl;main()derive op;return 0;11.2.2派生派生类的构造函数和析构函数的构造的构造函数和析构函数的构造规则l派生派生类构造函数的一般格式:构造函数的一般格式:l在定在定义派生派生类对象象时,构造函数的,构造函数的执行行顺序如序如下:下
13、:(1)基基类的构造函数的构造函数 (2)对象成象成员的构造函数的构造函数 (3)派生派生类的构造函数的构造函数l例例11.7派生派生类构造函数名(参数表):基构造函数名(参数表):基类构构造函数名(参数表),造函数名(参数表),对象成象成员名名1(参数表)(参数表),对象成象成员名名n(参数表)(参数表)派生派生类中其它数据成中其它数据成员初始化初始化【例例11.7】派生派生类构造函数构造函数给基基类构造函数构造函数传递参数。参数。#include class baseint x;public:base(int a)cout基基类类的构造函数的构造函数endl;x=a;base()cout基
14、基类类的析构函数的析构函数endl;void showx()coutxendl;class derived:public baseint y;public:derived(int a,int b):base(a)/派生派生类类的构造函数,要的构造函数,要缀缀上基上基类类的构造函数的构造函数 cout派生派生类类的构造函数的构造函数endl;y=b;derived()cout派生派生类类的析构函数的析构函数endl;void showy()coutyendl;void main()derived obj(10,20);obj.showx();obj.showy();return 0;含有含有对象
15、成象成员的派生的派生类构造函数构造函数l当派生当派生类中含有中含有对象成象成员时,派生,派生类必必须负责该对象成象成员的构造,其构造函数的一的构造,其构造函数的一般形式般形式为:派生派生类构造函数名构造函数名(参数表参数表):):基基类构造函构造函数名数名(参数表参数表),),对象成象成员名名1(1(参数表参数表),),对象成象成员名名n(n(参数表参数表)/【例例11.8】含有含有对象成象成员的派生的派生类构造函数的构造函数的执行情况行情况#include class baseint x;public:base(int a)cout基基类类的构造函数的构造函数endl;x=a;base()c
16、out基基类类的析构函数的析构函数endl;void showx()coutxendl;class derived:public basepublic:base d;/d为为基基类对类对象,作象,作为为派生派生类类的的对对象成象成员员derived(int a,int b):base(a),d(b)/派生派生类类的构造函数,的构造函数,缀缀上基上基类类构造函数构造函数/和和对对象成象成员员的构造函数的构造函数 cout派生派生类类的构造函数的构造函数endl;derived()cout派生派生类类的析构函数的析构函数endl;void main()derived obj(10,20);obj.
17、showx();obj.d.showx();说说明明l当基当基类的构造函数不的构造函数不带参数参数时,派生,派生类不一定需要不一定需要定定义构造函数,然而当基构造函数,然而当基类的构造函数那怕只的构造函数那怕只带有有一个参数,它所有的派生一个参数,它所有的派生类都必都必须定定义构造函数,构造函数,甚至所定甚至所定义的派生的派生类的构造函数的函数体有可能的构造函数的函数体有可能为空,空,仅仅起到参数起到参数传递作用。作用。l若基若基类使用缺省构造函数或不使用缺省构造函数或不带参数的构造函数,参数的构造函数,则在派生在派生类中定中定义构造函数构造函数时可略去,此可略去,此时若派生若派生类也不需要构
18、造函数,也不需要构造函数,则可以不定可以不定义构造函数。构造函数。l如果派生如果派生类的基的基类也是一个派生也是一个派生类,则每个派生每个派生类只需要只需要负责直接基直接基类的构造。的构造。l由于析构函数是不由于析构函数是不带参数的,在派生参数的,在派生类中是否要定中是否要定义析构函数与它所属的基析构函数与它所属的基类无关。无关。11.3 多重多重继承承l多重多重继承承:一个派生一个派生类具有多个基具有多个基类。在多重在多重继承中,公有承中,公有继承和私有承和私有继承承对于于基基类成成员在派生在派生类中的可中的可访问性与性与单继承承相同。相同。玩具玩具车车玩具车玩具车class 派生派生类名:
19、名:继承方式承方式1 基基类名名1,继承方式承方式n 基基类名名n 派生派生类新定新定义成成员;11.3.1 多重多重继承的声明承的声明例例11.9 声明多重派生。声明多重派生。#includeclass Xint a;public:void setX(int x)a=x;void showX()couta=aendl;class Yint b;public:void setY(int y)b=y;void showY()coutb=bendl;class Z:public X,private Yint c;public:void setZ(int x,int y)c=x;setY(y);vo
20、id showZ()showY();coutc=cendl;void main()Z obj;obj.setX(3);obj.showX();/obj.setY(4);/obj.showY();obj.setZ(6,8);obj.showZ();二二义义性性l对基基类成成员的的访问必必须是无二是无二义性的。性的。l消除下例中的二消除下例中的二义性,可写性,可写为obj.X:f();/调用用类X的的f()obj.X:f();/调用用类Y的的f()例例11.10多重多重继承承时,对基基类访问存在二存在二义性的情况。性的情况。#includeclass base1public:void show()
21、;class base2public:void show();class derive:public base1,private base2public:void showderive();void main()derive obj;obj.show();/二二义性性错误,不知,不知调用的是用的是 /base1的的show()/还是是base2的的show()11.3.2 多重多重继承的构造函数承的构造函数多重多重继继承构造函数定承构造函数定义义的一般形式如下:的一般形式如下:派生类构造函数名派生类构造函数名(参数表参数表):基类构造函:基类构造函数名数名1(参数表参数表),基类构造函数名,基
22、类构造函数名2(参数参数表表),基类构造函数名,基类构造函数名n(参数表参数表)/派生类中其它数据成员初始化派生类中其它数据成员初始化 【例例11.8】含有含有对象成象成员的派生的派生类构造函数的构造函数的执行情况。行情况。#include class baseint x;public:base(int a)cout基基类的构造函数的构造函数endl;x=a;base()cout基基类的析构函数的析构函数endl;void showx()coutxendl;class derived:public basepublic:base d;/d为基基类对象,作象,作为派生派生类的的对象成象成员der
23、ived(int a,int b):base(a),d(b)/派生派生类的构造函数,的构造函数,缀上基上基类构造函数构造函数/和和对象成象成员的构造函数的构造函数 cout派生派生类的构造函数的构造函数endl;derived()cout派生派生类的析构函数的析构函数endl;void main()derived obj(10,20);obj.showx();obj.d.showx();11.4 虚基虚基类l当引用派生当引用派生类的成的成员时,首先在派生,首先在派生类自身的作自身的作用域中用域中寻找找这个成个成员,如果没有找到,如果没有找到,则在它的在它的基基类中中寻找。如果一个派生找。如果一
24、个派生类是从多个基是从多个基类派生派生出来的,而出来的,而这些基些基类又有一个共同的基又有一个共同的基类,则在在这个派生个派生类中中访问这个共同的基个共同的基类中的成中的成员时,可能会可能会产生二生二义性。性。lvirtual 关关键字,同字,同继承方式关承方式关键字的先后字的先后顺序序无关无关紧要。要。【例例11.12】多重派生】多重派生产产生二生二义义性的情况性的情况#includeclass baseprotected:int a;public:base()a=5;class base1:public basepublic:base1()coutbase1 a=aendl;class b
25、ase2:public basepublic:base2()coutbase2 a=aendl;class derived:public base1,public base2public:derived()coutderived a=aendl;main()derived obj;return 0;derivedbase1base2basebase非虚基类的类层次图非虚基类的类层次图l如果采用虚基如果采用虚基类,则会消除二会消除二义性性derivedbase1base2base 虚基类的类层次图虚基类的类层次图虚基虚基类类的初始化的初始化l虚基虚基类构造函数的构造函数的调用用顺序序(1)若同一
26、)若同一层次中包含多个虚基次中包含多个虚基类,这些虚基些虚基类的构造函数按的构造函数按对它它们的的说明先后次序明先后次序调用。用。(2)若虚基)若虚基类由非虚基由非虚基类派生而来,派生而来,则仍然先仍然先调用基用基类的构造函数,再的构造函数,再调用派生用派生类的构造函数。的构造函数。(3)若同一)若同一层次中同次中同时包含虚基包含虚基类和非虚基和非虚基类,应先先调用虚基用虚基类的构造函数,再的构造函数,再调用非虚基用非虚基类的的构造函数,最后构造函数,最后调用派生用派生类的构造函数。的构造函数。应应用用举举例例data_recStaff:virtual data_recstudent:virt
27、ual data_recstudent_staffprofessor应用虚基用虚基类构建学生、学校构建学生、学校职员、教授、兼、教授、兼职学学校校职员的学生之的学生之间的的类关系。关系。lstudent last_name;first_namestreet_address;citystate;zip;majorid_number;level;lStafflast_name;first_namestreet_address;citystate;zip;depthourly_wage;Student_stafflast_name;first_namestreet_address;citystate
28、;zip;majormajor id_number;id_number;level;level;deptdept hourly_wage;hourly_wage;11.5 小小结l继承的重要性是支持程序代承的重要性是支持程序代码复用,它不复用,它不仅能能够从已存在的从已存在的类中派生出新中派生出新类,新,新类能能够继承基承基类的成的成员,而且可以通,而且可以通过重重载基基类成成员函数,函数,产生新的行生新的行为。l本章介本章介绍了了C+中中继承的概念与用法;承的概念与用法;单一一继承和多重承和多重继承的概念;派生承的概念;派生类的构造的构造函数和析构函数的构造函数和析构函数的构造规则;虚基;虚基类的引的引入和用法等。入和用法等。