首页 第七章继承与派生

第七章继承与派生

举报
开通vip

第七章继承与派生第七章继承与派生数学与统计科学学院胡凤珠C++语言程序设计(第4版)目录7.1类的继承与派生7.2访问控制7.3类型兼容规则7.4派生类的构造、析构函数7.5派生类成员的标识与访问*7.1类的继承与派生*7.1类的继承与派生巴巴爸爸和巴巴妈妈巴巴祖 巴巴拉拉巴巴利波巴巴伯巴巴贝尔 巴巴布莱特巴巴布莱伯7.1类的继承与派生*属性:姓名:巴巴爸爸颜色:粉红色横坐标x:0纵坐标y:0行为(动作):移动位置#include“string.h”classBarbapapa{stringname;//private私有数据成员...

第七章继承与派生
第七章继承与派生数学与统计科学学院胡凤珠C++语言程序设计(第4版)目录7.1类的继承与派生7.2访问控制7.3类型兼容规则7.4派生类的构造、析构函数7.5派生类成员的标识与访问*7.1类的继承与派生*7.1类的继承与派生巴巴爸爸和巴巴妈妈巴巴祖 巴巴拉拉巴巴利波巴巴伯巴巴贝尔 巴巴布莱特巴巴布莱伯7.1类的继承与派生*属性:姓名:巴巴爸爸颜色:粉红色横坐标x:0纵坐标y:0行为(动作):移动位置#include“string.h”classBarbapapa{stringname;//private私有数据成员stringcolor;floatx;floaty;public://公有函数成员voidmove(floatx2,floaty2){x+=x2;y+=y2;}Barbapapa(stringname1,stringcolor1,floatx1=0,floaty1=0){name=name1;color=color1;x=x1;y=y1;}};7.1类的继承与派生*7.1类的继承派生属性:姓名:巴巴布莱特颜色:蓝色横坐标x:0纵坐标y:0行为(动作):移动位置实验#include“test.h”#include“string.h”classBarbulaite{stringname;//private私有数据成员stringcolor;floatx;floaty;public://公有函数成员voidmove(floatx2,floaty2){x+=x2;y+=y2;}Barbulaite(stringname1,stringcolor1,floatx1=0,floaty1=0){name=name1;color=color1;x=x1;y=y1;}voidtest();};*属性:姓名:巴巴布莱特颜色:蓝色横坐标x:0纵坐标y:0行为(动作):移动位置实验voidBarbulaite::test();{intn;cout<<“请输入1-5整数实验编号”<>n;switch(n){case1:test1();break;case2:test2();break;case3:test3();break;case4:test4();break;case5:test5();break;}7.1类的继承与派生----引例属性:姓名:巴巴爸爸颜色:粉红色横坐标x:0纵坐标y:0行为(动作):移动位置属性:姓名:巴巴布莱特颜色:蓝色横坐标x:0纵坐标y:0行为(动作):移动位置实验7.1类的继承与派生classBarbapapaclassBarbulaite可否实现代码重用保持已有类的特性而构造新类的过程称为继承。在已有类的基础上新增自己的特性而产生新类的过程称为派生。被继承的已有类称为基类(或父类)。派生出的新类称为派生类。*7.1类的继承与派生——1、派生与继承的定义classBarbapapaclassBarbulaite*7.1类的继承与派生——1、派生与继承的定义classBarbapapaclassBarbulaiteclass派生类名:继承方式基类名{成员声明;}派生类的声明格式*7.1类的继承与派生——2、派生类的定义三种继承方式:公有继承私有继承保护继承classD:publicB1,privateB2{intm;//新增数据成员public:D();//构造函数~D();//析构函数voidprint(){cout<<“子类新增函数跟踪”;}//新增成员函数};例如:派生类从基类继承(除了构造和析构函数)成员之外的所有成员,还可以新增及改造成员。#inlude“test.h”classBarbulaite{stringname;stringcolor;floatx;floaty;public:voidmove(floatx2,floaty2){x+=x2;y+=y2;}Barbulaite(stringname1,stringcolor1,floatx1=0,floaty1=0){name=name1;color=color1;x=x1;y=y1;}voidtest();};//实现部分略*7.1类的继承与派生classBarbapapa{stringname;stringcolor;floatx;floaty;public:voidmove(floatx2,floaty2){x+=x2;y+=y2;}Barbapapa(stringname1,stringcolor1,floatx1=0,floaty1=0){name=name1;color=color1;x=x1;y=y1;}};*7.1类的继承与派生classBarbapapa{stringname;stringcolor;floatx;floaty;public:Barbapapa(stringname1,stringcolor1,floatx1=0,floaty1=0){name=name1;color=color1;x=x1;y=y1;}voidmove(floatx2,floaty2){x+=x2;y+=y2;}};#inlude“test.h”classBarbulaite:publicBarbapapa{//新增数据成员无,可以省略public:Barbulaite();//构造函数~Barbulaite();//析构函数voidtest();//添加新的成员函数voidmove(floatx2,floaty2)//改造的成员{x+=x2*2;y+=y2*2;}};//实现部分略classBarbapapa{……};classBarbamama{……}; classBarbalala:publicBarbapapa,publicBarbamama{……};7.1类的继承与派生——3、继承的种类一个派生类,可以同时有多个基类,这种情况称为多继承。*classBarbapapa{……};classBarbulaite:publicBarbapapa{……};一个派生类只有一个直接基类的情况,称为单继承。直接参与派生出某类的基类称为直接基类。7.1类的继承与派生——3、继承的种类 classBarbalala:publicBarbamama{……};classBarbapapa{……};classBarbamama:publicBarbapapa{……};基类的基类甚至更高层的基类称为间接基类。巴巴爸爸和巴巴妈妈巴巴贝尔7.1类的继承与派生——3、继承的种类派生新类经历了三个步骤:吸收基类成员吸收基类成员之后,派生类实际上就包含了它的全部基类中除构造和析构函数之外的所有成员。改造基类成员如果派生类声明了一个和某基类成员同名的新成员(如果是成员函数,则参数表也要相同,参数不同的情况属于重载),派生的新成员就覆盖了外层同名成员。添加新的成员派生类新成员的加入是继承与派生机制的核心,是保证派生类在功能上有所发展。*7.1类的继承与派生——4、派生类生成过程class派生类名:继承方式基类名{成员声明;}; classBarbalala:publicBarbapapa,publicBarbamama{……};派生类可以吸收基类中除构造和析构函数之外的所有成员。声明了一个和基类成员同名的新成员(如果是成员函数,则参数表也要相同),派生的新成员就覆盖了外层同名成员。派生类中添加新成员,也可以是其他成员的重载函数。7.2访问控制7.2.1公有继承(public)7.2.2私有继承(private)7.2.3保护继承(protected)不同继承方式的影响主要体现在:派生类成员函数(类体内)对基类成员的访问权限通过派生类对象(类体外)对基类成员的访问权限*以7.1类的继承与派生继承举例为例。classBarbapapa{stringname;stringcolor;floatx;floaty;public:Barbapapa(stringname1,stringcolor1,floatx1=0,floaty1=0){name=name1;color=color1;x=x1;y=y1;}voidmove(floatx2,floaty2){x+=x2;y+=y2;}};#inlude“test.h”classBarbulaite:publicBarbapapa{//新增数据成员无,可以省略public:Barbulaite();//构造函数~Barbulaite();//析构函数voidtest();//添加新的成员函数voidmove(floatx2,floaty2)//改造的成员{x+=x2*2;y+=y2*2;}};//实现部分略voidmain(){Barbulaitet;cout<w=w;this->h=h;}floatgetH()const{returnh;}floatgetW()const{returnw;}private://新增私有数据成员floatw,h;};#endif//_RECTANGLE_H//Point.h#ifndef_POINT_H#define_POINT_HclassPoint{//基类Point类的定义public://公有函数成员voidinitPoint(floatx=0,floaty=0){this->x=x;this->y=y;}voidmove(floatoffX,floatoffY){x+=offX;y+=offY;}floatgetX()const{returnx;}floatgetY()const{returny;}private://私有数据成员floatx,y;};#endif//_POINT_H*#include#includeusingnamespacestd;intmain(){Rectanglerect;//执行默认的构造函数rect.initRectangle(2,3,20,10);//设置矩形的数据rect.move(3,2);//移动矩形位置cout<<"Thedataofrect(x,y,w,h):"<w=w;this->h=h;}232010xywh调用voidinitPoint(floatx=0,floaty=0){this->x=x;this->y=y;}23201023xy#include#includeusingnamespacestd;intmain(){Rectanglerect;//执行默认的构造函数rect.initRectangle(2,3,20,10);//设置矩形的数据rect.move(3,2);//移动矩形位置cout<<"Thedataofrect(x,y,w,h):"<#includeusingnamespacestd;intmain(){Rectanglerect;//执行默认的构造函数rect.initRectangle(2,3,20,10);//设置矩形的数据rect.move(3,2);//移动矩形位置cout<<"Thedataofrect(x,y,w,h):"<x=x;this->y=y;}voidmove(floatoffX,floatoffY){x+=offX;y+=offY;}floatgetX()const{returnx;}floatgetY()const{returny;}private://私有数据成员floatx,y;};#endif//_POINT_H基类public:initPoint、move、getX、getYprotected:无private:x,y*//Rectangle.h#ifndef_RECTANGLE_H#define_RECTANGLE_H#include"Point.h"classRectangle:privatePoint{//派生类定义部分public://新增公有函数成员voidinitRectangle(floatx,floaty,floatw,floath){initPoint(x,y);//调用基类公有成员函数this->w=w;this->h=h;}voidmove(floatoffX,floatoffY){Point::move(offX,offY);}floatgetX()const{returnPoint::getX();}floatgetY()const{returnPoint::getY();}floatgetH()const{returnh;}floatgetW()const{returnw;}private://新增私有数据成员floatw,h;};#endif//_RECTANGLE_H改造了从基类处继承的成员函数从基类处继承的三个成员函数:voidmove(floatoffX,floatoffY){x+=offX;y+=offY;}floatgetX()const{returnx;}floatgetY()const{returny;}*#include#includeusingnamespacestd;intmain(){Rectanglerect;//定义Rectangle类的对象rect.initRectangle(2,3,20,10);//设置矩形的数据rect.move(3,2);//移动矩形位置cout<<"Thedataofrect(x,y,w,h):"<classA{public:voidf1();protected:intj1;private:inti1;};classB:publicA{public:voidf2();protected:intj2;private:inti2;};回答下述问题:①派生类B中成员函数f2()能否访问基类A中的成员f1(),i1,j1?②派生类B中对象b能否访问基类A中的成员f1(),i1和j1?7.2.1公有继承(public)7.2.2私有继承(private)7.2.3保护继承(protected)1、派生类有几个成员,从基类处继承几个?新增几个?2、派生类的成员的访问属性?在派生类体内、类体外可否访问?3、派生类改造和增加成员的方法。4、函数重载也是有作用域的,基类中的成员函数可以重载,派生类中的成员函数可以重载。#includeusingnamespacestd;//基类classShape{public:voidsetWidth(intw){width=w;}voidsetHeight(inth){height=h;}protected:intwidth;intheight;};//派生类classRectangle:publicShape{public:intgetArea(){return(width*height);}};intmain(void){RectangleRect;Rect.setWidth(5);Rect.setHeight(7);//输出对象的面积cout<<"Totalarea:"<usingnamespacestd;classA//基类A{inta;public:voidprint1(){a=1;cout<<"执行基类A中的print1函数"<<"a="<usingnamespacestd;classA//基类A{inta;public:voidprint1(){a=1;cout<<"执行基类A中的print1函数"<<"a="<usingnamespacestd;classB1//基类B1{public:voiddisplay()const{cout<<"执行B1的display函数"<display();}intmain(){B1b1;B2b2;Dd1;fun(&b1);//用B1类对象的指针调用fun函数fun(&b2);//用B2类对象的指针调用fun函数fun(&d1);//用D类对象的指针调用fun函数return0;}*****派生类的对象可以隐含转换为基类对象。派生类的对象可以初始化基类的引用。派生类的指针可以隐含转换为基类的指针。但是通过基类对象名、指针只能使用从基类继承的成员。建议不要重新定义继承而来的非虚函数。7.4派生类的构造、析构函数单继承派生类只从一个基类派生。多继承派生类从多个基类派生。多重派生由一个基类派生出多个不同的派生类。多层派生派生类又作为基类,继续派生新的类。*基类的构造函数不被继承,派生类中需要声明自己的构造函数。定义构造函数时:需要对本类中新增成员进行初始化;对继承来的基类成员的初始化,自动调用基类构造函数完成。派生类的构造函数需要给基类的构造函数传递参数。*派生类名::派生类构造函数名(基类所需的形参,本类成员所需的形参):基类名(参数表){本类成员初始化赋值语句;};*#includeusingnamespacestd;classB{public:B();B(inti);~B();voidprint()const;private:intb;};B::B(){b=0;cout<<"B'sdefaultconstructorcalled."<(p1.getX()-p2.getX());doubley=static_cast(p1.getY()-p2.getY());len=sqrt(x*x+y*y);}Line::Line(Line&l):p1(l.p1),p2(l.p2){//组合类的拷贝构造函数cout<<"CallingthecopyconstructorofLine"<usingnamespacestd;classBase1{//基类Base1,构造函数有参数public:Base1(inti){cout<<"ConstructingBase1"<usingnamespacestd;classBase1{//基类Base1,构造函数有参数public:Base1(inti){cout<<"ConstructingBase1"<usingnamespacestd;classBase1{//定义基类Base1public:intvar;voidfun(){cout<<"MemberofBase1"<Base2::var=3;//作用域分辨符标识p->Base2::fun();//访问Base2基类成员}7.5派生类成员的标识与访问——7.5.1作用域分辨二义性问题在多继承时,基类与派生类之间,或基类之间出现同名成员时,将出现访问时的二义性(不确定性)——采用虚函数或同名隐藏规则来解决。当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生二义性——采用虚基类来解决。*7.5派生类成员的标识与访问——7.5.1作用域分辨多继承派生类从多个基类派生。二义性问题举例(1)classA{public:voidf();};classB{public:voidf();voidg()};classC:publicA,piblicB{public:voidg();voidh();};如果定义:Cc1;则c1.f()具有二义性而c1.g()无二义性(同名隐藏)*7.5派生类成员的标识与访问——7.5.1作用域分辨二义性的解决方法解决方法一:用类名来限定c1.A::f()或c1.B::f()*7.5派生类成员的标识与访问——7.5.1作用域分辨classA{public:voidf();};classB{public:voidf();voidg()};classC:publicA,piblicB{public:voidg();voidh();};如果定义:Cc1;则c1.f()具有二义性而c1.g()无二义性(同名隐藏)二义性的解决方法解决方法二:同名隐藏在C中声明一个同名成员函数f(),f()再根据需要调用A::f()或B::f()*7.5派生类成员的标识与访问——7.5.1作用域分辨classA{public:voidf();};classB{public:voidf();voidg()};classC:publicA,piblicB{public:voidg();voidh();};如果定义:Cc1;则c1.f()具有二义性而c1.g()无二义性(同名隐藏)例7-7多继承同名隐藏举例(2)//7_7.cpp#includeusingnamespacestd;classBase0{//定义基类Base0public:intvar0;voidfun0(){cout<<"MemberofBase0"<B-->D这条路径,另一份来自A-->C-->D这条路径。7.5派生类成员的标识与访问//间接基类AclassA{protected:intm_a;};//直接基类BclassB:virtualpublicA{//虚继承protected:intm_b;};//直接基类CclassC:virtualpublicA{//虚继承protected:intm_c;};//派生类DclassD:publicB,publicC{public:voidseta(inta){m_a=a;}//正确voidsetb(intb){m_b=b;}//正确voidsetc(intc){m_c=c;}//正确voidsetd(intd){m_d=d;}//正确private:intm_d;};intmain(){Dd;return0;}使用虚继承,在派生类D中就只保留了一份成员变量m_a,直接访问不会有歧义。虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。这个被共享的基类就称为虚基类(VirtualBaseClass),A是一个虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。图2:使用虚继承解决菱形继承中的命名冲突问题C++标准库中的iostream类就是一个虚继承的实际应用 案例 全员育人导师制案例信息技术应用案例心得信息技术教学案例综合实践活动案例我余额宝案例 。iostream从istream和ostream直接继承而来,而istream和ostream又都继承自一个共同的名为base_ios的类。此时istream和ostream必须采用虚继承,否则将导致iostream类中保留两份base_ios类的成员。图3:虚继承在C++标准库中的实际应用7.5派生类成员的标识与访问7.5.2虚基类---强调虚基类的引入用于有共同基类的场合声明以virtual修饰说明基类例:classB1:virtualpublicB作用主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题.为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝注意:在第一级继承时就要将共同基类设计为虚基类。*7.5派生类成员的标识与访问*7.5派生类成员的标识与访问——7.5.2虚基类#includeusingnamespacestd;classBase0{//定义基类Base0public:intvar0;voidfun0(){cout<<"MemberofBase0"<usingnamespacestd;classBase0{//定义基类Base0public:Base0(intvar):var0(var){}intvar0;voidfun0(){cout<<"MemberofBase0"<usingnamespacestd;classStudent{public:Student(char*name,intage,floatscore);public:friendvoidshow(Student*pstu);//将show()声明为友元函数private:voidprint(){cout<<"执行Student类中的私有成员函数"<m_name<<"的年龄是"<m_age<<",成绩是"<m_score<print();}intmain(){Studentstu("张军",15,90.6);show(&stu);//调用友元函数Student*pstu=newStudent("梦圆",16,80.5);show(pstu);//调用友元函数return0;}//2)将其他类的成员函数声明为友元函数#includeusingnamespacestd;classAddress;//提前声明Address类//声明Student类classStudent{public:Student(char*name,intage,floatscore);public:vo
本文档为【第七章继承与派生】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
个人认证用户
DNSJDS
暂无简介~
格式:ppt
大小:5MB
软件:PowerPoint
页数:98
分类:
上传时间:2021-12-01
浏览量:1