它允许程序员在保持原有类特性的基础上进行扩展,增加功

上传人:hy****d 文档编号:243324744 上传时间:2024-09-21 格式:PPT 页数:34 大小:124.50KB
返回 下载 相关 举报
它允许程序员在保持原有类特性的基础上进行扩展,增加功_第1页
第1页 / 共34页
它允许程序员在保持原有类特性的基础上进行扩展,增加功_第2页
第2页 / 共34页
它允许程序员在保持原有类特性的基础上进行扩展,增加功_第3页
第3页 / 共34页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,继承(inheritance):,继承是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构。,体现了由简单到复杂的认识过程,。,继承与派生,继承,(inheritance)可对类(class)分层, C+通过,类的派生,(class derivation)的机制来支持继承。被继承的类称为,基类,(base class)或,超类,(superclass),新的类为,派生类,(derived class)或(subclass)。,派生反映了事物之间的联系,事物的共性与个性之间的关系。 派生与独立设计若干相关的类,前者工作量少,重复的部分可以从基类继承来,不需要单独,编程实现代码复用,。,1,继承与派生的概念,虚基类,多重继承与派生类成员标识,派生类应用讨论,派生类的构造函数与析构函数,继承与派生,2,一、类的派生与继承,二、公有派生与私有派生,继承与派生的概念,3,、派生类的定义格式:,class,派生类名:访问限定符 基类名1,访问限定符,基类名2,访问限定符 基类名n,private,:,成员表1;,/派生类增加或替代的私有成员,public,:,成员表2;,/派生类增加或替代的公有成员,protected,:,成员表3;,/派生类增加或替代的保护成员,;,/分号不可少,其中基类1,基类2,是已声明的类。,在派生类定义的类体中给出的成员称为,派生类成员,,它们是,新增加,成员,它们给派生类添加了不同于基类的新的属性和功能。派生类成员也包括取代基类成员的更新成员。,一、类的派生与继承,4,基类1,基类2,基类n,派生类1,派生类2,基类,派生类1,派生类2,(,a,)多重继承,(,b,)单继承,多重继承与单继承,一个基类可以直接派生出多个派生类,派生类可以由多个基类共同派生出来,称多重继承。,、多重继承:,如果一个派生类可以同时有多个基类,称为多重继承(multiple-inheritance)。,、单继承:,派生类只有一个直接基类称为单继承(single-inheritance)。,5,在派生过程中,派生出来的新类同样可以作为基类再继续派生出更新的类,依此类推形成一个层次结构。直接参与派生出某类称为直接基类,而基类的基类,以及更深层的基类称为,间接基类,。,类族:,同时一个基类可以直接派生出多个派生类。这样形成了一个相互关联的类族。如MFC就是这样的族类,它由一个CObject类派生出200个MFC类中的绝大多数。,、多层次继承:,一、类的派生与继承,6,)、吸收基类的成员,)、改造基类成员,)、发展新成员,)、重写构造函数与析构函数,不论是数据成员,还是函数成员,除构造函数与析构函数外全盘接收,声明一个和某基类成员同名的新成员,派生类中的新成员就屏蔽了基类同名成员称为同名覆盖(override),派生类新成员必须与基类成员不同名,它的加入保证派生类在功能上有所发展。,、派生编程步骤:,编制派生类时可分四步,7,注意:,在第二步中,,新成员如是成员函数,参数表也必须一样,,否则是重载。,第三步中,独有的新成员才是继承与派生的核心特征。,第四步是重写构造函数与析构函数,派生类不继承这两种函数。不管原来的函数是否可用,一律重写可免出错,。,8,6、访问控制:,亦称为,继承方式,,是对基类成员进一步的限制,访问控制有三种:,公有(,public,)方式,亦称公有继承,保护(,protected,)方式,亦称保护继承,私有(,private,)方式, 亦称私有继承。,不可直接访问,不可直接访问,private,不可直接访问,private,protected,不可直接访问,private,public,私有派生,不可直接访问,不可直接访问,private,不可直接访问,protected,protected,可直接访问,public,public,公有派生,在派生类对象外访问派生类对象的基类成员,在派生类中对基类成员的访问限定,基类中的访问限定,派生方式,9,例题:分析下列程序的访问权限,并回答所提出的问题,#include,class A,public :void f1();,protected:int j1;,private:int i1;,;,class B:public A,public:,void f2();,protected:,int j2;,private:,int i2;,;,class C:public B,public:,void f3();,;,回答下列问题:,1、派生类B中成员函数f2()能否访问基类A 中的成员:f1(),i1,j1?,2、派生类B的对象能否访问基类A 中的成员:f1(),i1,j1?,3、派生类C中的成员函数能否访问基类B 中的成员:f2(),i2,j2?,10,1、派生类构造函数的定义:,派生类名:派生类名(参数总表):基类名1(参数名表1),基类名2(参数名表2),基类名n(参数名表n),成员对象名1(成员对象参数名表1),成员对象名m(成员对象参数名表m),/派生类新增成员的初始化;,/所列出的成员对象名全部为新增成员对象的名字,注意:,1)在构造函数的声明中,冒号及冒号以后部分必须略去。,2),基类名仅指直接基类,写了底层基类,编译器认为出错,。,3)冒号后的基类名,成员对象名的次序可以随意,这里的次序与调用次序无关。,派生类的构造函数与析构函数,11,2、派生类构造函数各部分执行次序:,1)调用基类构造函数,按它们在派生类定义的先后顺序,顺序调用。,2)调用成员对象的构造函数,按它们在类定义中声明的先后顺序,顺序调用。,3)派生类的构造函数体中的操作。,注意:,1)在派生类构造函数中,只要基类不是使用无参的默认构造函数都要显式给出基类名和参数表。,2)如果基类没有定义构造函数,则派生类也可以不定义,全部采用系统给定的默认构造函数。,3)如果基类定义了带有形参表的构造函数时,派生类就应当定义构造函数。,12,3、析构函数:,析构函数,的功能是作善后处理工作。,派生类的析构函数只需把派生类新增一般成员处理好就可以了,而对新增的成员对象和基类的善后工作,系统会自己调用成员对象和基类的析构函数来完成。,析构函数各部分执行次序与构造函数相反,,首先对派生类新增一般成员析构,然后对新增对象成员析构,最后对基类成员析构。,13,例题:分析下列程序 的输出结果,代码一:,#include,class A,public:,A()a=0;cout“As default constructor called.n”;,A(int i)a=i,;cout“As constructor called.n”);,A()cout“ As destructor called.n”;,void Print() const couta“,”,int GetA()return a;,private:,int a;,14,class B:public A,public:,B (),b=0;,cout“As default constructor called.n”;,B(int I,int j,int k);,B()cout“Bs destructor called.n”;,void Print();,private:,int b;,A aa;,;,B:B(int I,int j,int k):A(i),aa(j),b=k;,cout“Bs constructor called”;,void B:;Print(),A;:Print();,coutb“,”aa.Geta()endl;,void main(),B bb2;,bb0=B(1,2,5);,bb1=3,4,7;,for(int i=0;i2;i+),bbi.Print();,15,代码二:,#include,class M,public:,M()m1=m2=0;,M(int I,int j)m1=I;m2=j;,void print()coutm1“,”m2“,”;,M()cout“Ms destructor called.n”;,private:,int m1,m2;,;,class N:public M,public:,N()n=0;,N(int I,int j,int k);,void print(),M:print();,coutnendl;,N(),cout“Ns destructor calledn”;,private:,int n;,N:N(int I,int j,int k):M(I,j),n(k),void mian(),N n1(5,6,7);,n2(-2,-3,-4);,n1.print(),n2.print();,16,例题:由“人”类派生出“学生”类。我们希望基类和派生类共享相同的公有方法,因此,只能采用公有派生来实现。,人类:,enum Tsexmid,man,woman;,class Person,string IdPerson;/身份证号,18位数字,string Name;/姓名,Tsex Sex; /性别,int Birthday;/生日,格式1986年8月18日写作19860818,string HomeAddress;/家庭地址,public:,Person(string, string,Tsex,int, string);/,构造函数,Person(); /,默认的构造函数,Person(); /,析构函数,17,void SetName(string);,/,修改名字,string GetName()return Name;,/提取名字,void SetSex(Tsex sex)Sex=sex; /修改性别,Tsex GetSex()return Sex; /提取性别,void SetId(string id)IdPerson=id;/修改身份证号,string GetId()return IdPerson;,/提取身份证号,void SetBirth(int birthday),Birthday=birthday; /修改生日,int GetBirth()return Birthday; /提取生日,void SetHomeAdd(string ); /,修改住址,string GetHomeAdd()return HomeAddress;,/提取住址,void PrintPersonInfo(); /,输出个人信息,;,/接口方法:,18,派生的学生类:,class,Student:,public,Person,/定义派生的学生类,string NoStudent;,/学号,course cs30;,/30门课程与成绩,public,:,Student(string id, string name,Tsex sex,int,birthday,string homeadd, string nostud);,/注意,派生类构造函数,声明方式,Student();,/,默认派生类构造函数,Student();,/,派生类析构函数,SetCourse(string ,int,);,/,课程设置,int,GetCourse(string );,/,查找成绩,void,PrintStudentInfo();,/,打印学生情况,;,struct,course,string coursename;,int,grade;,19,人,学生(单继承),教职工(单继承),兼职教师(单继承),教师(单继承),行政人员(单继承),工人(单继承),研究生(单继承),行政人员兼教师,(多重继承),在职研究生,(多重继承),研究生助教,(多重继承),学校人员与人继承关系,派生出来的新类同样可以作为基类再继续派生出更新的类,依此类推形成一个,层次结构,。,多重继承与派生类成员标识,多重继承实例:,20,二义性问题:,在上图中,比如行政人员兼教师,在其基类教师中有一个“教职工编号”,另一基类行政人员中也有一个“教职工编号”,如果只讲教职工编号到底那是哪一个基类中的呢?或者这两者是一回事?,解决的方法:,1)通常采用作用域分辨符“:”,进行区别:,基类名:成员名;,/数据成员,基类名:成员名(参数表);,/函数成员,2)引入”虚基类”,多重继承与派生类成员标识,21,例题:分析下列程序的输出结果,#include,class A,public:,A(int i)a=I;cout“con An”;,void print()coutaendl;,A()cout“des An”;,private:,int a;,;,class B1:public A,public :,B1(int I,int j):A(i)b1=j;cout“con B1n”;,void print(),A:print();,coutb1ednl;,B1()coutdes B1n”;,private:,int b1;,;,class B2:public A,public:,B2(int I,int j):A(i),b2=j;cout“con B2n”;,22,void print(),A:print();,coutb2ednl;,B2()coutdes B2n”;,private:,int b2;,;,class C:public B1,B2,public:,C(int I,int j,int k,int l,int m):B1(I,j),B2(k,l),c(m),cout“con Cn”;,void print(),B1:print();,B2:print();,coutcendl;,C()cout“des Cn”;,private:int c;,;,void main(),C c1(1,2,3,4,5);,c1.print();,result:,con A1,con B1,con A,con B2,con c,1,2,3,4,5,des C,des B2,des A,des B1,des A,23,注意:,virtual,关键字只对紧随其后的基类名起作用:,例如:,class,Student:,virtual,public,Person.;,class,Employee:,virtual public,Person.;,一、虚基类,(virtual base class),定义:,class,派生类名:,virtual,访问限定符 基类类名.;,或,class,派生类名:访问限定符,virtual,基类类名.;,虚基类,24,例如:,class A,public:,void f();,protected:,int a;,;,class B:virtual public A,protected:,int b;,class C:virtual public A, protected:,int c;,class D:public B,public C,public:,int g();,private:,int d;,由于使用了虚基类,使得类A,类B,类C和类D之间的关系用DAG图示法表示如下:,Af(),a,Bb Cc,Dg(),d,25,说明:引进虚基类后,派生类的对象中只有一个虚基类的子对象。当一个类有虚基类时,编译系统将为该类的对象定义一个指针成员,让它指向虚基类的子对象。该指针被称为虚基类指针。上例中,各类的存储结构如下图所示:,B,C,A,D,虚基类指针,26,二、虚基类的构造函数,如果一个派生类有一个直接或者间接的虚基类,那么派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用,如果未列出,则表示使用该虚基类的缺省构造函数来初始化派生类对象中的虚基类子对象。,从虚基类直接或者间接继承的派生类中的构造函数的成员初始化列表中都要列出这个虚基类构造函数的调用。但是,只有最后的派生类对象调用虚基类的构造函数,而该派生类的基类中所列出的对这个虚基类的构造函数的调用在执行中被忽略。,在一个成员初始化列表中出现对虚基类和非虚基类构造函数的调用,则虚基类的构造函数先于非虚基类的构造函数的执行。,27,例题:分析下列程序的输出结果,#include,class A,public:,A(const char *s),coutsendl;,A(),;,class B:virtual public A,public:,B(const char *s1,const char *s2):A(s1),couts2endl;,class C:virsual public A,public:,C(const char *s1,const char *s2):A(s1),couts2endl;,;,class D:public B,public C,public:,D(const char *s1,const char *s2,const *s3,const *s4):B(s1,s2),C(s1,s3),A(s1),couts4endl;,;,28,void main(),D *ptr=new D(“class A”,”class B”,”class C”,”class D”);,delete ptr;,运行结果:,class A,class B,class C,class D,29,例题:分析下列程序的输出结果,#include class A public: int n; ; class B:public A; class C:public A; class D:public B,public C int getn()return B:n; ; void main() D d; d.B:n=10; d.C:n=20; coutd.B:n,d.C:nendl; ,D类是从类B和类C派生的而类B和类C又都是从类A派生的,但各有自己的副本。所以对于对象d,d.B:n与d.C:n是两个不同的数据成员它们互无联系。 所以输出为: 10,20,30,例题:假设图书馆的图书包含书名、编号、作者属性,读者包含姓名和借书证属性,每位读者最多可借5本书,编写程序列出某读者的借书情况。,分析:设计一个类,从它派生出图书类book和读者类reader,在reader类中有一个rentbook()成员函数用于借阅图书。 程序代码如下:,#include #include class object char name20; int no; public: object() object(char na,int n) strcpy(name,na);no=n; void show() coutname“(”no“)”; ;,31,class book:public object char author10; public: book() book(char na,int n,char auth):object(na,n) strcpy(author,auth); void showbook() show(); cout作者:author; ; void main() book b1(C语言,100,谭浩强),b2(数据结构,110,严蔚敏); reader r1(王华,1234); r1.rentbook(b1); r1.rentbook(b2); r1.showreader(); ,32,class reader:public object book rent5; int top; public: reader(char na,int n):object(na,n)top=0; void rentbook(book ,void main() book b1(C+语言,101,谭浩强),b2(数据结构,110,严蔚敏); reader r1(王华,1234); r1.rentbook(b1); r1.rentbook(b2); r1.showreader(); ,33,总结:,1. 派生类具有基类的所有成员,。,2. 派生类的构造函数自动执行基类的构造函数,且基类的构造函数先执行。基类构造函数的参数由派生类传递。,3. 派生类中可对已有的成员进行重新定义。,4.可定义多重派生类。且可利用虚基类使派生类只保持一个基类的成员拷贝,。,34,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


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

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


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