C++实用教程[郑阿奇主编]12

上传人:小*** 文档编号:243776982 上传时间:2024-09-30 格式:PPT 页数:55 大小:328KB
返回 下载 相关 举报
C++实用教程[郑阿奇主编]12_第1页
第1页 / 共55页
C++实用教程[郑阿奇主编]12_第2页
第2页 / 共55页
C++实用教程[郑阿奇主编]12_第3页
第3页 / 共55页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,*,*,第,12,章 继承和派生,12.1,继承和派生概述,12.1.1,继承的概念,1.,继承和概括,继承(,Inheritance,),是指一个事物可以继承其父辈全部或部分特性,同时本身还有自己的特性。,2.,类继承相关概念,在,C+,中,当一个新类从一个已定义的类中派生后,新类不仅继承了原有类的属性和方法,并且还拥有自己新的属性和方法,称为类的继承和派生。被继承的类称为基类(,Base class,)或超类(,Super class,)(又称父类),在基类或父类上建立的新类称为派生类(,Derived class,)或子类(,Sub class,)。,3.,类层次关系的描述方法上述父类和子类的关系称为类层次或继承关系。在类设计时,常常将这些关系用树来描述。例如,下图就是用树来描述学校人员类的层次关系。,12.1.2,继承的特性,在,C+,中,类的继承具有下列特性:,(,1,)单向性。,(,2,)传递性。,(,3,)可重用性。,12.1.3,派生类的定义,在,C+,中,一个派生类的定义可按下列格式:,class : , , ,;,12.2,继承方式,C+,继承方式有三种:,public,(公有)、,private,(私有)及,protected,(保护),12.2.1,公有继承,公有继承(,public,)方式具有下列特点:,(,1,)在派生类中,基类的公有成员、保护成员和私有成员的访问属性保持不变。,(,2,)派生类对象只能访问派生类和基类的公有(,public,)成员。,例,Ex_PublicDerived,派生类的公有继承示例。,#include ,#include ,using namespace std;,class,CPerson,public:,CPerson(char,*name,int,age, char sex = M),strncpy(this,-name, name, 20);,this-age =,age,;this-sex =,sex,;,void,SetNameAndSex,( char *name, char sex = M) /,更改姓名和性别,strncpy(this,-name, name, 20);this-sex =,sex,;,protected:,void,SetAge(int,age),this-age =,age,;,void,ShowInfo,()/,显示信息,cout,姓名:,name,endl,;,cout,性别:,(sex=M?,男,:,女,),endl,;,cout,年龄:,age,stuno, no, 20);,void,SetScore,( float s1, float s2, float s3 ),score0 = s1;score1 = s2;score2 = s3;,total = s1 + s2 + s3;,ave,= total / (float)3.0;,void,SetNoAndAge(char,*no,int,age),strncpy(this,-,stuno, no, 20);this-,SetAge,( age );,void,ShowAll,(),ShowInfo,();/,调用基类的成员函数,cout,学号:,stuno,endl,;,cout,三门成绩:,score0tscore1tscore2,endl,;,cout,总成绩和平均分:,totalt,ave,endl,;,private:,charstuno20;/,学号,floatscore3,ave, total;/,三门成绩、平均分和总分,;,int,main(),CStudent,one(LiMing, 21050101, 19 );/ A,one.SetScore,( 90, 80, 84);/ B,one.ShowAll,();/,调用派生类的公有成员函数,one.SetNameAndSex(WangFang, W);,/,调用基类的公有成员函数,one.SetNoAndAge(21050102, 18 );,/,调用派生类的公有成员函数,one.ShowAll,();/,调用派生类的公有成员函数,return 0;,程序运行结果如下:,12.2.2,私有继承,私有继承(,private,)方式具有下列特点:,(,1,)在派生类中,基类的公有成员、保护成员和私有成员的访问属性都将变成私有(,private,),且基类的私有成员在派生类中被隐藏。,(,2,)由于基类的所有成员在派生类中都变成私有的,因此基类的所有成员在派生类的子类中都是不可见的。,(,3,)派生类对象只能访问派生类的公有成员,不能访问基类的任何成员。,例,Ex_PrivateDerived,派生类的私有继承示例。,#include ,#include ,using namespace std;,class,CPerson,public:,CPerson(char,*name,int,age, char sex = M),strncpy(this,-name, name, 20);,this-age =,age,;this-sex =,sex,;,void,SetNameAndSex,( char *name, char sex = M),/,更改姓名和性别,strncpy(this,-name, name, 20);this-sex =,sex,;,protected:,void,SetAge(int,age),this-age =,age,;,void,ShowInfo,()/,显示信息,cout,姓名:,name,endl,;,cout,性别:,(sex=M?,男,:,女,),endl,;,cout,年龄:,age,stuno, no, 20);,public:,void,SetScore,( float s1, float s2, float s3 ),score0 = s1;score1 = s2;score2 = s3;,total = s1 + s2 + s3;,ave,= total / (float)3.0;,void,SetNoAndAge(char,*no,int,age),strncpy(this,-,stuno, no, 20);this-,SetAge,( age );,void,ShowAll,(),ShowInfo,();/,调用基类的保护成员函数,cout,学号:,stuno,endl,;,cout,三门成绩:,score0tscore1tscore2,endl,;,cout,总成绩和平均分:,totalt,ave,endl,;,/,修改的代码,void,SetNameAndSex,( char *name, char sex = M)/,更改姓名和性别,CPerson:,SetNameAndSex(name, sex); /,调用基类的公有成员函数,private:,charstuno20;/,学号,floatscore3,ave, total;,/,三门成绩、平均分和总分,;,int,main(),CStudent,one(LiMing, 21050101, 19 );,one.SetScore,( 90, 80, 84);,one.ShowAll,();,one.SetNameAndSex(WangFang, W);,one.SetNoAndAge(21050102, 18 );,one.ShowAll,();,return 0;,程序运行结果同前。,12.2.3,保护继承,保护继承(,protected,)方式具有下列特点:,(,1,)在派生类中,基类的公有成员、保护成员的访问属性都将变成保护的。,(,2,)同私有继承一样,在保护继承方式下,派生类中仍可访问基类的公有成员和保护成员。,12.3,派生类的构造和析构,12.3.1,构造和析构次,1.,单继承,如图,12.2,(,a,)所示,,A,类是,B,类的基类,,B,类又是,C,类的基类,它们是多层单继承方式,其代码如下:,class A,public:,A(),cout,执行,A,的构造函数,endl,;,A(),cout,执行,A,的析构函数,endl,;,;,class B: public A,public:,B(),cout,执行,B,的构造函数,endl,;,B(),cout,执行,B,的析构函数,endl,;,;,class C: public B,public:,C(),cout,执行,C,的构造函数,endl,;,C(),cout,执行,C,的析构函数,endl,;,;,int,main(),C c;,return 0;,程序运行结果如下,2.,多继承如图,12.2,(,b,)所示,类,A,和类,B,是,C,类的基类,它们是多继承方式,其代码如下:,class A,public:,A(),cout,执行,A,的构造函数,endl,;,A(),cout,执行,A,的析构函数,endl,;,;,class B,public:,B(),cout,执行,B,的构造函数,endl,;,B(),cout,执行,B,的析构函数,endl,;,;,class C:,public B, public A,public:,C(),cout,执行,C,的构造函数,endl,;,C(),cout,执行,C,的析构函数,endl,;,;,int,main(),C c;,return 0;,程序运行结果如下:,执行,B,的构造函数,执行,A,的构造函数,执行,C,的构造函数,执行,C,的构造函数,执行,A,的构造函数,执行,B,的构造函数,12.3.2,派生类数据成员初始化,一个派生类的构造函数的定义可有下列格式:,(,形参表,),:,基类,1,(,参数表,),基类,2,(,参数表,), ,基类,n,(,参数表,),对象成员,1(,参数表,),对象成员,2,(,参数表,), ,对象成员,n,(,参数表,), ,成员初始化列表,例如,一个长方体类,CCuboid,,它从基类矩形类,CRect,派生而来。基类,CRect,的数据成员是两个,CPoint,类对象,ptLT,和,ptRB,,分别表示矩形的左上角点和右下角点的位置。派生类,CCuboid,自身的数据成员有表示高度的,fHeight,,表示底面中点位置的,CPoint,对象,ptCenter,,如右图所示。具体程序如下。,例,Ex_ClassDerived,派生类的构造和析构示例。,#include ,using namespace std;,class,CPoint,public:,CPoint,(,int,x = 0,int,y = 0)/,C,xPos,= x;,yPos,= y;,cout,CPoint,构造函数,endl,;,void,ShowPos(bool,isEnd,= false),cout,pos(,xPos, ,yPos,);,if (,isEnd,),cout,endl,;,private:,int,xPos,yPos,;,;,class,CRect,public:,CRect,(,int,x1 = 0,int,y1 = 0,int,x2 = 0,int,y2 = 0),/ B,: ptLT(x1, y1), ptRB(x2, y2),cout,CRect,构造函数,endl,;,void,ShowPos,(),ptLT.ShowPos,();,cout, ;,ptRB.ShowPos(true,);,private:,CPoint,ptLT,ptRB,;,;,class,CCuboid,:,public,CRect,public:,CCuboid,(,int,x1,int,y1,int,x2,int,y2,int,height ),/ A,: CRect(x1, y1, x2, y2),ptCenter(x1+x2)/2, (y1+y2)/2),fHeight(height,),cout,CCuboid,构造函数,endl,;,void,ShowAll,(),cout,矩形的角点为:,;,CRect:ShowPos,();,cout,底面矩形的中点为:,;,ptCenter.ShowPos(true,);,cout,高为:,fHeight,endl,;,private:,CPoint,ptCenter,;,float,fHeight,;,;,int,main(),CCuboid,one( 5, 5, 30, 30, 50);,one.ShowAll,();,return 0;,程序运行结果如下:,12.4,二义性和虚基类,12.4.1,二义性概述,一般来说,在派生类中对基类成员的访问应该是唯一的。但是多继承或多层继承可能造成对基类中某成员的访问出现不唯一的情况,这种情况称为基类成员调用的二义性。,二义性出现的情况可以有下列两种。,1.,同名成员来源于不同的基类,例,Ex_Conflict1,同名成员来源于不同的基类,#include ,using namespace std;,class A,public:,int,x;,A(int,a = 0) x = a; ,;,class B,public:,int,x;,B(,int,a = 0,int,b = 0) x = a; ,;,class C :,public B, public A,public:,int,z;,C(int,a,int,b,int,c),:,A(a,),B(b,),z = c;,void print(),cout,x = x,endl,;,/,编译出错的地方,cout,z = z,endl,;,;,int,main(),C c1(100,200,300);,c1.print();,return 0;,程序中,派生类,C,同时继承了,A,和,B,这两个基类,由于基类,A,和基类,B,都有数据成员,x,,当编译到“,coutx = xendl;”,语句时,无法确定成员,x,是来自基类,A,还是来自基类,B,,因此产生了二义性,从而出现编译错误。解决这个问题的简单方法是使用域作用运算符“,:”,来消除二义性,即将,print,函数实现代码改为:,void print(),cout,A:x,= ,A:x,endl,;,cout,B:x,= ,B:x,endl,;,cout,z = z,endl,;,重新运行的结果如下,2.,同名成员来源于同一个基类,例,Ex_Conflict2,同名成员来源于同一个基类。,#include ,using namespace std;,class A,public:,int,x;,A(int,a = 0) x = a; ,;,class B1 : public A,public:,int,y1;,B1(,int,a = 0,int,b = 0),:,A(b,),y1 = a;,;,class B2 : public A,public:,int,y2;,B2(,int,a = 0,int,b = 0),:,A(b,),y2 = a;,;,class C : public B1, public B2,public:,int,z;,C(int,a,int,b,int,d,int,e,int,m),:B1(a,b), B2(d,e),z = m;,void print(),cout,x = x,endl,;/,编译出错的地方,cout,y1 = y1, y2 = y2,endl,;,cout,z = z,endl,;,;,int,main(),C c1(100,200,300,400,500);,c1.print();,return 0;,程序中,,B1,类和,B2,类都是从基类,A,继承的派生类,这时在继承,B1,和,B2,的派生类,C,中就有两个基类,A,的拷贝。当编译器编译到“,coutx = xendl;”,语句时,因无法确定成员,x,是从类,B1,中继承来的,还是从类,B2,继承来的,因此产生二义性,从而出现了编译错误。,解决这个问题仍可使用前面的方法,即使用域作用运算符“,:”,通过指定基类来消除二义性。例如,可将,print,函数实现代码改写为,void print(),cout,B1:x = B1:x,endl,;,cout,B2:x = B2:x,endl,;,cout,y1 = y1, y2 = y2,endl,;,cout,z = z,endl,;,重新运行后的结果如下:,12.4.2,二义性解决方法,(,1,)当派生类和其基类中都有一个成员,X,时,在派生类中访问的,X,就是派生类的成员,X,,这是,C+,中类的局部优先原则。,(,2,)若,A,类是,B,类的基类,,B,类是,C,类的基类,当,A,类和,B,类都有一个成员,X,时,则在子类,C,中访问的,X,是,B,类的成员,这是,C+,中类的最近优先原则。,对于出现二义性的第,1,种情况,指定作用域是最好的解决方法。但对于第,2,种情况,指定作用域虽是一种解决方法,但不是最好的办法。因为在派生类,C,中总有两个基类,A,的拷贝,不仅多占用内存,而且效率也不高。为此在实际应用中多采用虚基类的形式来解决。,12.4.3,虚基类和虚继承,1.,虚基类的定义,虚基类不是指基类是虚的,而是指在派生类中指定的基类是虚继承方式,即使用下列格式定义派生类的继承方式:,class : virtual ,;,例,Ex_VirtualBase,虚基类的使用示例。,#include ,using namespace std;,class A,public:,int,x;,A(int,a = 0) x = a; ,;,class B1 : virtual public A/,声明虚继承,public:,int,y1;,B1(,int,a = 0,int,b = 0),:,A(b,),y1 = a;,void,print(void,),cout,B1: x = x, y1 = y1,endl,;,;,class B2 : virtual public A/,声明虚继承,public:,int,y2;,B2(,int,a = 0,int,b = 0),:,A(b,),y2 = a;,void,print(void,),cout,B2: x = x, y2 = y2,endl,;,;,class C : public B1, public B2,public:,int,z;,C(int,a,int,b,int,d,int,e,int,m),:B1(a,b), B2(d,e),z = m;,void print(),B1:print();B2:print();,cout,z = z,endl,;,;,int,main(),C c1(100,200,300,400,500);c1.print();,c1.x = 400;c1.print();,return 0;,程序运行结果如下:,2.,虚基类的实质,在上述示例中,类,A,、,B1,、,B2,和,C,的层次关系可用图,12.5,来表示,图,12.5,类的层次关系,12.5,兼容,兼容是指在公有派生情况下,一个派生类对象可以赋给基类对象,这种情况又称为赋值兼容,或称类型自动转换,。,12.5.1,赋值兼容规则,简单地讲,对于公有派生类来说,可以将派生类的对象直接赋给其基类对象,反之却不可以。,12.5.2,赋值兼容机理,例,Ex_CastTest,派生类赋值兼容测试示例。,#include ,#include ,using namespace std;,class CA,public:,CA(int,x = 0) a = x; ,int,getA,() return a; ,private:,int,a;,;,class CB,public:,CB(int,x = 0) b = x; ,int,getB,() return b; ,private:,int,b;,;,class CC: public CB, public CA,public:,CC(,int,y = 0) c = y;,int,getC,() return c; ,private:,int,c;,;,int,main(),CC *c = new CC(5);,cout,getC,(),getB,(),getA,(),endl,;,CA a(3);,CB b(4);,memcpy(CA,*,)c, &a,sizeof(a,);/ A,memcpy(CB,*,)c, &b,sizeof(b,);/ B,cout,getC,(),getB,(),getA,(),endl,;,delete c;,return 0;,程序运行结果如下:,Ex_CastOther,派生类赋值兼容其他情况示例。,#include ,#include ,using namespace std;,class CA,public:,CA(int,x = 0) a = x; ,int,getA,() return a; ,void,ShowAddr,(),cout,CA,对象的地址:,(,unsigned)this,endl,;,cout,ta,的地址:,(,unsigned)&a,endl,;,private:,int,a;,;,class CB,public:,CB(int,x = 0) b = x; ,int,getB,() return b; ,void,ShowAddr,(),cout,CB,对象的地址:,(,unsigned)this,endl,;,cout,tb,的地址:,(,unsigned)&b,endl,;,private:,int,b;,;,class CC: public CB, public CA,public:,CC(,int,y = 0)c = y;,int,getC,() return c; ,void,ShowAddr,(),CA:ShowAddr,();,CB:ShowAddr,();,cout,CC,对象的地址:,(,unsigned)this,endl,;,cout,tc,的地址:,(,unsigned)&c,endl,;,private:,int,c;,;,int,main(),CC c(5);/ c,对象中的数据成员,c,为,5,cout,- CC c(5);-,endl,;,c.ShowAddr,();,cout,- CA *a = -,ShowAddr,();,cout,- CB -,endl,;,CB / B,b.ShowAddr,();,b = CB(4);,*a = CA(3);,cout,c.getC,(),c.getB,(),c.getA,(),endl,;,return 0;,程序运行结果如下:,12.6,综合应用实例,12.6.1,类间关系,1.,继承关系,2.,组合关系,3.,共享关系,12.6.2,设计实例,例,Ex_Multi12,综合应用实例,#include ,#include ,using namespace std;,class,CPerson,public:,CPerson,(),CPerson(char,*name,int,age, char sex = M),strncpy(this,-name, name, 20);,this-age =,age,;this-sex =,sex,;,void,ShowInfo,()/,显示信息,cout,姓名:,name,endl,;,cout,性别:,(sex=M?,男,:,女,),endl,;,cout,年龄:,age,classname,strname, 20);,strncpy(this,-,stuno,stuno, 20);,score0 = s1;score1 = s2;score2 = s3;,total = s1 + s2 + s3;,ave,= total / (float)3.0;,void,ShowInfo,(),cout,班级:,classname,endl,;,cout,学号:,stuno,endl,;,cout,三门成绩:,score0tscore1tscore2,endl,;,cout,总成绩和平均分:,totalt,ave,title, title, 20);,strncpy(this,-part, part, 20);,this-,workyears,= years;,void,ShowInfo,(),cout,职称:,title,endl,;,cout,部门:,part,endl,;,cout,工龄:,workyears,duty, duty, 20);,tutor.SetData,( title, part, years );,void,ShowInfo,(),cout,导师信息:,endl,;,tutor.ShowInfo,();,cout,职责:,duty,endl,;,private:,CTeacher,tutor;,charduty20;/,职责,;,int,main(),CAssistant,one( DING, 38, M, WANG, 19 );,one.SetData,( ,批改作业, ,教授, ,机电学院, 15 );,one.CStudent:SetData,( ,机电班, 210101, 80, 90, 80 );,one.CTeacher:SetData,( ,助课, ,机电学院, 2 );,one.CTeacher:ShowInfo,();,one.CStudent:ShowInfo,();,one.ShowInfo,();,return 0;,程序运行结果如下:,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 小学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!