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