




已阅读5页,还剩58页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第五章 继承与派生51继承与派生的概念(P150)一、为什么要使用继承通过继承的机制,可以利用已有的类来定义新的类,所定义的新类型拥有原来类型的属性,同时还拥有新的属性。继承的目的在于实现代码的重用。称已存在用来生成新的类型的类为基类,而由已存在类派生出来的新类为派生类。派生类继承了基类,即派生类中拥有基类中所有成员,并且派生类本身还拥有它自己的新成员。例如:已建有学生基本数据类 Studentclass Studentpublic: void display( ) coutnum: numendl; coutname: nameendl; coutsex: sexendl; private : int num; string name; char sex; 欲创建学生档案类1 Student1class Student1public: void display( ) coutnum: numendl; coutname: nameendl; coutsex: sexendl; coutage: ageendl; coutaddress: addrendl; private : int num; string name; char sex;int age; string addr; 二、单继承与多继承一个派生类只有一个直接基类的情况,称为单继承,一个派生类同时有多个基类的情况,称为多继承。XYZABC 单继承 多继承5.2 派生类的声明方式(P153)单继承派生类的一般定义格式class 派生类名:继承方式 基类名/派生类新增的数据成员和成员函数说明:(1)三种继承方式:公有继承:class Student1:public Student/.;私有继承:class Student1: private Student/.;保护继承:class Student1: protected Student/.;例如:class Student1:public Studentpublic: void display1( ) coutage: ageendl; coutaddress: addrendl; private : int age; string addr; 5.3 派生类的构成(p154) 基类 派生类成员函数Student类int num;string name;char sex;void display();Student1类int num;string name;char sex;void display();int age;string addr;void display1();继承新增数据成员1. 派生类继承了基类的所有成员;2. 增加新的成员;3. 改变现有成员的属性和重新定义基类中已有的成员函数。5.4 派生类成员的访问属性*基类成员在派生类中的访问属性三种不同的继承方式导致原来具有不同访问属性的基类的成员在派生类中具有不同的访问属性。在基类中的访问属性继承方式在派生类中的访问属性privatepublic不可直接访问privateprivate不可直接访问privateprotected不可直接访问publicpublicpublicpublicprivateprivatepublicprotectedprotectedprotectedpublicprotectedprotectedprivateprivateprotectedprotectedprotected从表中归纳出:(1)基类中的私有成员无论哪种继承方式,基类中的私有成员在派生类中都不可直接访问;(2)基类中的公用成员当类的继承方式为公用继承时,基类中的所有公用成员在派生类中仍以公用成员的身份出现;当类的继承方式为私有继承时,基类中的所有公用成员在派生类中都是以私有成员的身份出现;当类的继承方式为保护继承时,基类中的所有公用成员在派生类中都是以保护成员的身份出现。(3)基类中的保护成员当类的继承方式为公用继承时,基类中的所有保护成员在派生类中仍以保护成员的身份出现;当类的继承方式为私有继承时,基类中的所有保护成员在派生类中都是以私有成员的身份出现;当类的继承方式为保护继承时,基类中的所有保护成员在派生类中仍以保护成员的身份出现。5.4.1 公用继承公有继承的特点是:基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的,在派生类中是不可访问的。例5.1 访问公有基类的成员#include #include using namespace std;class Studentpublic: void get_value() cinnumnamesex; void display( ) coutnum: numendl; coutname: nameendl; coutsex: sexageaddr; void display_1() /coutnum: numendl; /企图引用基类的私有成员,错误 /coutname: nameendl; /企图引用基类的私有成员,错误 /coutsex: sexendl; /企图引用基类的私有成员,错误 coutage: ageendl; /引用派生类的私有成员,正确 coutaddress: addrendl;/引用派生类的私有成员,正确 private: int age; string addr; ;int main() Student1 stud1; stud1.get_value(); stud1.get_value_1(); stud1.display(); stud1.display_1(); return 0;例:5.2 公有继承的访问规则#includeclass base /声明一个基类public: void setxy(int m,int n) x=m; y=n; void showxy() coutx=xendl; couty=yendl; private: int x; protected: int y;class A:public base /声明derived为base的公有派生类public: void setxyz(int m,int n,int l) setxy(m,n); /ok z=l; void showxyz() coutx=xendl; /error couty=yendl; /ok coutz=zendl; private: int z;main() A obj; obj.setxyz(30,40,50); obj.showxy(); /ok obj.setxy(20,30); obj.showxyz(); return 0;说明:(1) 在公有继承时,基类中的公有成员和保护成员可以被派生类的成员函数访问,基类中仅有公有成员才可被派生类的对象访问;(2) 基类无论怎样继承,他的私有成员对派生类而言都是不能直接访问的。表5.1 P1565.4.2 私有继承(P158)私有继承的特点是:每个成员,无论是public,protected还是private成员,在派生类中都是private成员,而且它们都不能再被派生类的子类所访问。例5.3 P159例5.2#include #include using namespace std;class Studentpublic: void display( ) coutnum: numendl; coutname: nameendl; coutsex: sexendl; private : int num; string name; char sex; class Student1: private Studentpublic: void display_1() display(); coutage: ageendl; /引用派生类的私有成员,ok coutaddress:addrendl;/引用派生类的私有成员0k private: int age; string addr;int main() Student1 stud1;stud1.display(); /errorstud1.display_1(); /ok stud1.age=18; /errorreturn 0;说明:私有继承时,派生类的成员函数可以访问基类中的公有成员和保护成员;但派生类的对象不能访问基类中的任何成员。例54 保护成员以私有方式被继承后的访问属性#includeclass base /声明一个基类public: void seta(int sa) a=sa; void showa() couta=aendl; protected: int a;class A:private base public: void setab(int sa,int sb) a=sa; b=sb; void showab() couta=aendl; coutb=bendl; protected: int b;class B:private A public: void setabc(int sa,int sb,int sc) setab(sa,sb); c=sc; void showabc() couta=aendl; /error 可改为:showab(); coutb=bendl; /ok coutc=cendl; private: int c;void main() base op1; op1.seta(1); op1.showa(); A op2; op2.setab(2,3); op2.showab(); B op3; op3.setabc(4,5,6); op3.showabc(); 注意:由于私有派生类限制太多,使用不方便,一般不常使用。5.43 保护成员和保护继承的访问规则(P161)保护继承的特点是:基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,而基类的私有成员仍然是私有的。例55保护继承的访问规则#includeclass base /声明一个基类public: int z; void setx(int i) x=i; int getx() return x; private: int x; protected: int y;class A:protected base public: int p; void setall(int a,int b,int c,int d,int e,int f);void show();private:int m;protected:int n;void A :setall(int a,int b,int c,int d,int e,int f) x=a; /error,可改为: setx(a); y=b; /ok z=c; /ok m=d; n=e; p=f;void A :show()coutx=xendl; /error coutx=getx()endl; /okcouty=yendl; /ok coutz=zendl; coutm=mendl; coutn=nendl; void main() A obj; obj.setall(1,2,3,4,5,6); obj.show(); coutp=obj.pendl; 表5.3 P161说明:保护成员和保护继承方式的作用:三种继承方式小结:(1)阅读P162表5.4 (2)阅读P162P163l 在派生类中,成员有四种不同的访问属性;l 类的成员在不同作用域中有不同的访问属性。例 5.6(P163例5.3)在派生类中引用保护成员include #include using namespace std;class Student /声明基类public: /基类公用成员 void display( ); protected : /基类保护成员 int num; string name; char sex;void Student:display( ) coutnum: numendl; coutname: nameendl; coutsex: sexendl;class Student1: protected Student /用protected继承方式声明一个派生类public: void display1( ); private: int age; string addr;void Student1:display1( )coutnum: numendl; /引用基类的保护成员,合法 coutname: nameendl;/引用基类的保护成员,合法 coutsex: sexendl; /引用基类的保护成员,合法 coutage: ageendl; /引用派生类的私有成员,合法 coutaddress:addrendl;/引用派生类的私有成员,okint main( ) Student1 stud1; /stud1是派生类student2的对象 stud1.display1( ); /display是派生类中的公用成员函数 return 0; 5.4.4 多级派生时的访问属性 (P164)例5.7 (P164例5.4)多级派生时的访问属性class A /基类 public: int i; protected: void f2(); int j; private: int k;class B: public A /public方式 public: void f3( ); protected: void f4(); private: int m;class C: protected B /protected方式 public: void f5(); private: int n;if2jkf3f4mf5n基类A公用保护保护私有公用派生类B公用保护保护不可访问公用保护私有保护派生类C保护保护保护不可访问保护保护不可访问公用私有从表中可以看出:l 在派生类C的外面,只能访问C的成员函数f5;l 派生类C的成员函数f5能访问基类A的成员i、f2、j和派生类B的成员f3,f4;l 派生类B的成员函数f3能访问基类A的成员i、f2、j.问题:私有成员k,m,n能被谁访问?结论:无论是哪一种继承方式,在派生类中是不能访问基类的私有成员,私有成员只能被本类的成员函数所访问。55 派生类的构造函数与析构函数551 简单的派生类的构造函数的构造原则(简单的派生类:只有一个基类,只有一级派生,不包含子对象)简单的派生类构造函数的一般格式:派生类名(总参数表列):基类名(参数表列) 派生类中新增数据成员初始化语句 例5.8 (P167例5.5)简单的派生类的构造函数#include #includeusing namespace std;class Student /声明基类public: /公用部分 Student(int n,string nam,char s ) /基类构造函数 num=n; name=nam; sex=s; Student( ) /基类析构函数 protected: /保护部分 int num; string name; char sex ; /基类析构函数;class Student1: public Student /声明公用派生类studentpublic: Student1(int n,string nam,char s,int a,string ad ) : Student(n,nam,s) /派生类构造函数 age=a; /在函数体中只对派生类新增的数据成员初始化 addr=ad; void show( ) coutnum: numendl; coutname: nameendl; coutsex: sexendl; coutage: ageendl; coutaddress: addrendlendl; Student1( ) /派生类析构函数 private: /派生类的私有部分 int age; string addr; ;int main( ) Student1 stud1(10010,Wang-li,f,19,115 Beijing Road,Shanghai ); Student1 stud2(10011,Zhang-fun,m,21,213 Shanghai Road,Beijing ); stud1.show( ); /输出第一个学生的数据 stud2.show( ); /输出第二个学生的数据 return 0;说明:(1)在建立一个派生类对象时,执行派生类构造函数的顺序为:先调用基类构造函数,再执行派生类构造函数本身;(2)在类中对派生类构造函数仅作声明时,不包括基类构造函数名及其参数表列,只在类外定义函数时才将其列出;例如:类内声明:Student1(int n,string nam,char s,int a,string ad ) ;类外定义:Student1(int n,string nam,char s,int a,string ad ) : Student(n,nam,s) age=a; /在函数体中只对派生类新增的数据成员初始化 addr=ad;(3)派生类构造函数也可采用参数列表的形式,例如:Student1(int n,string nam,char s,int a,string ad ) : Student(n,nam,s),age(a), addr(ad) 552 有子对象的派生类的构造函数的构造原则(P169)(有子对象的派生类: 新增的某个数据成员又是一个类的对象 )有子对象的派生类构造函数的一般格式:派生类名(总参数表列):基类名(参数表列),子对象名(参数表列) 派生类中新增数据成员初始化语句 例5.9 (P170例5.6)包含子对象的派生类的构造函数(在派生类Student1中增加“班长”一项,即学生数据中包含他们的班长的姓名和其他基本情况,而班长本身也是学生,属于Student类)#include #include using namespace std;class Student /声明基类 public: /公用部分 Student(int n,string nam) /基类构造函数 num=n; name=nam; void display() /输出基类数据成员 coutnum:numendlname:nameendl; protected: /保护部分 int num; string name;class Student1: public Student/用public继承方式声明派生类studentpublic: Student1(int n,string nam,int n1,string nam1,int a,string ad) :Student(n,nam),monitor(n1,nam1)/派生类构造函数 age=a; /在此处只对派生类新增的数据成员初始化 addr=ad; void show( ) coutThis student is:endl; display(); /输出num和name coutage: ageendl; coutaddress: addrendlendl; void show_monitor() /输出子对象的数据成员 coutendlClass monitor is:endl; monitor.display(); /调用基类成员函数 private: /派生类的私有数据 Student monitor; /定义子对象(班长) int age; string addr; ;int main( ) Student1 stud1(10010,Wang-li,10001,Li-sun,19,115 Beijing Road,Shanghai); stud1.show( ); /输出第一个学生的数据stud1.show_monitor(); /输出子对象的数据 return 0;说明:(1)在建立一个含有子对象的派生类对象时,执行派生类构造函数的顺序为:l 调用基类构造函数,对基类数据成员初始化;l 调用子对象构造函数,对子对象数据成员初始化;l 再执行派生类构造函数本身,对派生类新增数据成员初始化(2)派生类构造函数的总参数表列中的参数,应当包括基类构造函数和子对象的参数表列中的参数;(3)如果有多个子对象,则在派生类构造函数中应列出每一个子对象名及其参数表列。553 多层派生类时的构造函数每一层派生类的构造函数只需列出直接基类的构造函数即可。例5.10(P172例5.7)多级派生情况下派生类的构造函数#include #includeusing namespace std;class Student /声明基类public: /公用部分 Student(int n, string nam ) /基类构造函数 num=n; name=nam; void display() /输出基类数据成员 coutnum:numendl; coutname:nameendl; protected: /保护部分 int num; /基类有两个数据成员 string name;class Student1: public Student /声明公用派生类Student1public: /下面是派生类构造函数 Student1(int n,string nam,int a):Student(n,nam) age=a; /在此处只对派生类新增的数据成员初始化 void show( ) /输出num,name和age display(); /输出num和name coutage: ageendl; private: /派生类的私有数据 int age; /增加一个数据成员;class Student2:public Student1 /声明间接公用派生类student2public: /下面是间接派生类构造函数 Student2(int n,string nam,int a,int s):Student1(n,nam,a) score=s; void show_all() /输出全部数据成员 show(); /输出num和name coutscore:scoreendl; /输出age private: int score; /增加一个数据成员 ;int main( ) Student2 stud(10010,Li,17,89); stud.show_all( ); /输出学生的全部数据 return 0;分析:建立Student2派生类对象stud的构造函数执行顺序。调用:Student(n,nam);初始化基类数据成员num,name; 调用:Student1(n,nam,a);初始化Student1类中的数据成员age;再初始化Student2类中的数据成员score。554 派生类构造函数的特殊形式(P175) 阅读:P175554 派生类的析构函数(P175)例511基类和派生类构造函数和析构函数的执行顺序#includeclass basepublic: base() cout基类的构造函数endl; base() cout基类的析构函数endl; ;class derive:public base public: derive() cout派生类的构造函数endl; derive() cout派生类的析构函数endl; ;main() derive op; return 0;说明:构造函数的执行顺序:基类构造函数-子对象类构造函数(如果有子对象类)-派生类构造函数析构函数的执行顺序: 派生类构造函数-子对象类构造函数(如果有子对象类)-基类构造函数56 多继承(P176)561 多继承的声明多继承与单继承的区别仅在于它们基类的个数,有两个或两个以上的基类的派生类称为多继承派生类。例如: 玩具车玩具车多继承派生类的定义一般格式:class 派生类名:继承方式1 基类名1,。继承方式n 基类名n/派生类新增的数据成员和函数成员注:多继承的访问规则与单继承相同例:5.12 多继承情况下的访问特性#includeclass Apublic: void setA(int x) a=x; void printA() couta=aendl; private: int a;class Bpublic: void setB(int x) b=x; void printB( ) coutb=bendl; private: int b;class C: public A,private Bpublic: void setC(int x,int y) c=x; setB(y); void printC() printB(); coutc=cendl; private: int c;int main() C obj; obj.setA(3); obj.printA(); obj.setB(4); /error C对B是私有继承 obj.printB(); /error C对B是私有继承 obj.setC(6,8); obj.printC(); return 0;562 多继承派生类的构造函数与析构函数1 多继承的构造函数的一般形式派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),。基类名n(参数表n)/派生类新增数据成员的初始化语句说明:多继承派生类的构造函数与单继承派生类的构造函数相似,它必须同时负责该派生类所有基类构造函数的调用,同时,派生类的参数个数必须包含完成所有基类初始化所需的参数个数。例513 多继承中构造函数的定义方法#includeclass base1public: base1(int sx) /基类base1的构造函数 x=sx; int getx() return x; private: int x;class base2public: base2(int sy) /基类base1的构造函数 y=sy; int gety() return y; private: int y;class derived:public base1,private base2 public: derived(int sx,int sy,int sz):base1(sx),base2(sy) z=sz ; int getz() return z; int gety() return base2:gety(); private: int z;int main() derived obj(1,3,5); int ma=obj.getx(); coutx=maendl; int mb=obj.gety(); couty=mbendl; int mc=obj.getz(); coutz=mcendl; return 0; 例514(P176例5.8) 多继承的应用#include #include using namespace std;class Teacher /声明Teacher(教师)类public: /公用部分 Teacher(string nam,int a,string t)/构造函数 name=nam; age=a;title=t; /职称 void display() /输出教师有关数据 coutname:nameendl; coutageageendl; couttitle:titleendl; protected: /保护部分 string name; int age; string title; /职称;class Student /声明类Student(学生)public: Student(string nam,char s,float sco) name1=nam; sex=s; score=sco; /构造函数 void display1() /输出学生有关数据 coutname:name1endl; coutsex:sexendl; coutscore:scoreendl; protected: /保护部分 string name1; char sex; float score; /成绩 ;class Graduate:public Teacher,public Student /声明多重继承的派生类Graduate研究生public: /声明多重继承的派生类Graduate的构造函数 Graduate(string nam,int a,char s,string t,float sco,float w): Teacher(nam,a,t),Student(nam,s,sco),wage(w) void show( ) /输出人员的有关数据 coutname:nameendl; coutage:ageendl; coutsex:sexendl; coutscore:scoreendl; couttitle:titleendl; coutwages:wageendl; private: float wage; /工资;int main( ) Graduate grad1(Wang-li,24,f,assistant,89.5,1234.5); grad1.show( ); return 0;2多继承的构造函数与析构函数的执行顺序先执行所有基类的构造函数,再执行派生类本身的构造函数,包含子对象在内,其中,多个基类构造函数的执行顺序取决于定义派生类时所指定的多个基类的顺序。析构函数的执行顺序则与构造函数的执行顺序相反。563 多继承的“二义性”问题当两个或多个基类中有相同的成员名称时,即出现了“二义性”问题,编译器将无法理解使用的是哪个成员。例515:多继承中的“二义性”问题#includeclass father public:void disp() cout”姓名:李明“endl;class mo
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 图书发行合同3篇
- 预交保证金租房合同2篇
- 琵琶课件教学课件
- 甘孜建设工程检测方案(3篇)
- 福州净化工程方案(3篇)
- 理想信念课件
- 电网工程签证方案实例(3篇)
- 安全整改教育培训课件
- 农业温室智慧农业技术在国际市场的应用与发展研究报告
- 地质工程策划方案模板(3篇)
- 1.1 常见的植物(教学课件)科学青岛版二年级上册(新教材)
- 2025年人教部编版小学三年级语文上册全册单元测试题及答案(全套)
- 部编新教材小学五年级语文上册全册同步练习课堂作业课课练课时练
- 基层群众自治制度课件
- GA 568-2022警服夏执勤短袖衬衣
- 上肢主要神经损伤诊断
- GB/T 38381-2019新闻出版知识服务知识元描述
- GB/T 24600-2009城镇污水处理厂污泥处置土地改良用泥质
- GB/T 1839-2008钢产品镀锌层质量试验方法
- 检验科标本采集手册
- 07FD02防空地下室电气设备安装图集
评论
0/150
提交评论