《继承与派生 》PPT课件.ppt

上传人:小飞机 文档编号:5568485 上传时间:2023-07-29 格式:PPT 页数:124 大小:1.03MB
返回 下载 相关 举报
《继承与派生 》PPT课件.ppt_第1页
第1页 / 共124页
《继承与派生 》PPT课件.ppt_第2页
第2页 / 共124页
《继承与派生 》PPT课件.ppt_第3页
第3页 / 共124页
《继承与派生 》PPT课件.ppt_第4页
第4页 / 共124页
《继承与派生 》PPT课件.ppt_第5页
第5页 / 共124页
点击查看更多>>
资源描述

《《继承与派生 》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《继承与派生 》PPT课件.ppt(124页珍藏版)》请在三一办公上搜索。

1、第11章 继承与派生第12章 多态性与虚函数第13章 输入输出流第14章 C+工具,第4篇面向对象的程序设计,第11章 继承与派生,11.1 继承与派生的概念11.2 派生类的声明方式11.3 派生类的构成11.4 派生类成员的访问属性11.5 派生类的构造函数和析构函数11.6 多重继承11.7 基类与派生类的转换11.8 继承与组合11.9 继承在软件开发中的重要意义,面向对象程序设计有4个主要特点:抽象封装继承多态性面向对象技术强调软件的可重用性(software reusability)。C+语言提供了类的继承机制,解决了软件重用问题。,在C+中可重用性是通过继承(inheritanc

2、e)这一机制来实现的。继承是C+的一个重要组成部分。在C+中,所谓“继承”就是在一个已存在的类的基础上建立一个新的类。见图11.1示意。,11.1 继承与派生的概念,已存在的类(例如“马”)称为“基类(base class)”或“父类(father class)”。新建立的类(例如“公马”)称为“派生类(derived class)”或“子类(son class)”。见图11.2示意。,图11.1 图11.2,一个派生类只从一个基类派生,这称为单继承(single inheritance),这种继承关系所形成的层次是一个树形结构,见下图。箭头表示继承的方向,从派生类指向基类。,一个派生类不仅可

3、以从一个基类派生,也可以从多个基类派生。一个派生类有两个或多个基类的称为多重继承(multiple inheritance)。,关于基类和派生类的关系:派生类是基类的具体化,而基类则是派生类的抽象。,声明派生类的一般形式为:class 派生类名:继承方式 基类名派生类新增加的成员;继承方式包括:public(公用的),private(私有的)和protected(受保护的),如果不写此项,则默认为private(私有的)。,11.2 派生类的声明方式,派生类分为两大部分:一部分是从基类继承来的成员另一部分是在声明派生类时增加的部分每一部分均分别包括数据成员和成员函数。,11.3 派生类的构成,

4、构造一个派生类包括以下4部分工作:,派生类对象结构,对于下面的继承关系:class Father int a,b;public:/成员函数;class Son:public Father int c;public:/成员函数;,基类对象子类对象子类对象空间总是不小于基类对象,c,a,b,a,b,基类部分,子类添加部分,11.4 派生类成员的访问属性,继承可以公有继承,保护继承和私有继承。公有继承是普通继承,基类可以为大多数应用服务。也可以重复继承。保护继承是“单传”继承,只继承给自己的后代,应用是以子孙的公有成员函数来对外展开服务的。私有继承是“绝版”继承,该基类只继承直接的子类,而不考虑让子

5、类再继承下去。,public继承:基类的public成员,在派生类中成为public成员基类的protected成员,在派生类中成为protected 成员基类的private成员,在派生类中成为不可直接使用的成员,11.4.1 公有继承,表11.1公用基类在派生类中的访问属性,例:下面定义了两个具有单继承关系的类A和B,其中,A为基类,B为派生类:,class Aint x,y;public:void f();void g();class B:public Aint z;public:void h();,在C+中对派生类有以下几点规定:派生类除了拥有基类的所有成员(基类的构造函数和赋值操作符

6、重载函数除外)外,也可以具有新的成员。,class Aint x,y;public:void f();void g();class B:public Aint z;public:void h();,void main()B b;b.f();/A类中的 fb.g();/A类中的gb.h();/B类中的h,派生类的定义用于描述派生类与基类的差别。派生类中可以给出新的成员,也可以对基类的成员进行重定义。如果在派生类中对基类的某个成员进行重定义,则在派生类中对该成员的访问是针对派生类中重定义的成员。,class B:public Aint z;public:void f();void h()f();/

7、B类中的f g();/A类中的g;void main()B b;b.f();/B类中的 fb.g();/A类中的gb.h();/B类中的h,派生类成员名的作用域嵌套在基类的作用域中,对于基类的一个成员,如果派生类中没有定义与其同名的成员,则该成员名在派生类的作用域内可见,否则,该成员名在派生类的作用域内不直接可见,如果要使用,必须用基类名受限。例:,class B:public Aint z;public:void f();void h()f();/B类中的f A:f()/A类中的f;void main()B b;b.f();/B 类中的 fb.A:f();/A类中的f,即使派生类中定义了与基

8、类同名但参数不同的成员函数,基类的同名函数在派生类中的作用域中也是不直接可见的。例:,class B:public Aint z;public:void f(int);void h()f(1);/Ok f();/A:f()/Ok;void main()B b;b.f(1);/Okb.f();/b.A:f();/Ok,定义派生类时一定要见到基类的定义,否则编译程序无法确定派生类对象需占多大内存空间以及派生类中对基类成员的访问是否合法。例:,class A;class B:public Aint z;public:void h()g();/Error没有g的原型;B b;/Error无法确定 b

9、所需空间,如果在派生类中没有显式说明,基类的友元不是派生类的友元;如果基类是另一个类的友元,而该类没有显式说明,则派生类也不是该类的友元。派生类不能直接访问基类的私有成员,必须要通过基类的非私有成员函数来访问基类的私有成员。例:,class A int x,y;public:void f();void g()x;class B:public Aint z;public:void h()x/Error,x为基类的私有成员g();/Ok,通过函数g访问基类的私有成员x;,在派生类中对基类成员的访问一个类有两种用户:实例用户和派生类。例:一个类存在两个对外接口给实例用户使用:由类的public成员构

10、成提供给派生类使用:由类的public和protected成员构成,class A;class B:public A/派生类;void f()/实例用户 A a;,class A protected:int x,y;public:void f();class B:public A/派生类 void h()x/Ok y/Ok f();/Ok;void f()/实例用户 A a;a.x/Errora.y/Errora.f();/Ok;,类的聚集:一个类只有一个接口,即类的实例用户接口。例:以继承和聚集实现的代码重用。,class A public:void f();void g();class B

11、:public A public:void h();,class B A a;public:void f()a.f();void g()a.g();void h();,继承实现子类型,派生类可以看成基类的子类型。子类型的作用:发给基类对象的消息也能发给派生类对象,以及基类的对象标识可以标识派生类对象。,class A public:void f();class B:public A public:void g();,以下操作合法:A a,*p;B b,*q;b.f();a=b;p=/Error,用b去改变a的状态,属于b但不属于a的成员将被忽略,A类指针p指向B类对象b,例11.1 访问公有基

12、类的成员。Class Student/声明基类public:/基类公用成员 void get_value()cinnumnamesex;void display()cout num:numendl;cout name:nameendl;cout sex:sexendl;private:/基类私有成员 int num;char name8;char sex;class Student1:public Student/以public方式声明派生类Student1,public:void display_1()cout num:numendl;cout name:nameendl;/引用基类的私有成

13、员,错误 cout sex:sexendl;cout age:ageendl;/引用派生类的私有成员,正确 cout address:addrendl;/引用派生类私有成员,正确private:int age;char addr12;,结论:由于基类的私有成员对派生类来说是不可访问的,因此在派生类中的display_1函数中直接引用基类的私有数据成员num,name和sex是不允许的。只能通过基类的公用成员函数来引用基类的私有数据成员。,可以将派生类Student1的声明改为:class Student1:public Student/以public方式声明派生类Student1public:

14、void display_1()coutageaddr;private:int age;string addr;,可以这样写main函数:int main()Student1 stud;stud.get_value();stud.get_value_1();stud.display();stud.display_1();return 0;,void display_1()display();cout“age:“ageendl;cout“address:“addrendl;,void get_value_1()get_value();Cinageaddr;,private继承:基类的public

15、成员,在派生类中成为private 成员基类的protected成员,在派生类中成为private成员基类的private成员,在派生类中成为不可直接使用的成员,11.4.2 私有继承,表11.1私有基类在派生类中的访问属性,图11.7表示了各成员在派生类中的访问属性。,例11.2 将例11.1中的公用继承方式改为用私有继承方式(基类Student不改)。可以写出私有派生类如下:class Student1:private Student/用私有继承方式声明public:void display_1()cout“age:“ageendl;cout“address:“addrendl;priva

16、te:int age;char addr12;,int main()Student1 stud1;stud1.display();/错误stud1.display_1();/正确stud1.age=18;/错误return 0;,结论:(1)不能通过派生类对象(如stud1)引用从私有基类继承过来的任何成员。(2)派生类的成员函数不能访问私有基类的私有成员,但可以访问私有基类的公用成员。在派生类外不能通过派生类对象调用私有基类的公用成员函数,但可以通过派生类的成员函数调用私有基类的公用成员函数(此时它是派生类中的私有成员函数,可以被派生类的任何成员函数调用)。,可将上面的私有派生类的成员函数定

17、义改写为void display_1()display();/调用基类的公用成员函数 coutage:ageendl;/派生类的私有数据成员coutaddress:addrendl;/派生类的私有数据成员main函数可改写为int main()Student1 stud1;stud1.display_1();/Student1类的公用函数 return 0;,由于私有派生类限制太多,使用不方便,一般不常使用。,11.4.3 保护成员和保护继承,protected 继承:基类的public成员,在派生类中成为protected 成员基类的protected成员,在派生类中成为protected

18、成员基类的private成员,在派生类中成为不可直接使用的成员,表11.3基类成员在派生类中的访问属性,保护成员可以被派生类的成员函数引用。但不能被实例函数引用。,例:class B1 int a;void f()couta;public:int b;void g()couta;protected:int c;void k()couta;,对派生类:class B2:public B1public:void df()couta;/coutb;coutc;f();/g();k();,对实例函数void main()B1 b1;coutb1.a;/coutb1.b;coutb1.c;/b1.f()

19、;/b1.g();b1.k();/,(1)在派生类中,成员有4种不同的访问属性:,表11.4派生类中的成员的访问属性,例11.3 在派生类中引用保护成员。#include#include using namespace std;class Studentpublic:void display();protected:int num;string name;char sex;,void Student:display()coutnum:numendl;coutname:nameendl;coutsex:sexendl;class Student1:protected Studentpublic:

20、void display1();private:int age;char addr 12;,void Student1:display1()/定义派生类公用成员函数 coutnum:numendl;/基类的保护成员,合法 coutname:nameendl;coutsex:sexendl;coutage:ageendl;/派生类的私有成员,合法 coutaddress:addrendl;int main()Student1 stud1;stud1.display1();stud1.num=10023;/错误,外界不能访问保护成员return 0;,在派生类的成员函数中引用基类的保护成员是合法的

21、。保护成员和私有成员不同之处,在于把保护成员的访问范围扩展到派生类中。注意:在程序中通过派生类Student1的对象stud1的公用成员函数display1去访问基类的保护成员num.name和sex,不要误认为可以通过派生类对象名去访问基类的保护成员。私有继承和保护继承方式很容易搞错,一般不常用。,11.4.4 多级派生时的访问属性,图11.9,如果有图11.9所示的派生关系:类A为基类,类B是类A的派生类,类C是类B的派生类,则类C也是类A的派生类。类B称为类A的直接派生类,类C称为类A的间接派生类。类A是类B的直接基类,是类C的间接基类。在多级派生的情况下,各成员的访问属性仍按以上原则确

22、定。,例11.4 多级派生访问属性。class Apublic:int i;protected:void f2();int j;private:int k;,class B:public A public:void f3();protected:void f4();private:int m;class C:protected Bpublic:void f5();private:int n;,class B:public:void f3();int i;protected:void f4();void f2();int j;private:int m;,class C:public:void

23、f5();protected:void f4();void f2();int j;void f3();int i;private:int n;,在派生类中是不能访问基类的私有成员的,私有成员只能被本类的成员函数所访问,毕竟派生类与基类不是同一个类。在多级派生时:采用公用继承方式,那么直到最后一级派生类都能访问基类的公用成员和保护成员。采用私有继承方式,经过若干次派生之后,基类的所有的成员已经变成不可访问的了。采用保护继承方式,在派生类外是无法访问派生类中的任何成员的。经过多次派生后,很难记住哪些成员可以访问,哪些成员不能访问。,常用的是公用继承!,11.5 派生类的构造函数和析构函数,用户在声

24、明类时可以不定义构造函数,系统会自动设置一个默认的构造函数。在设计派生类的构造函数时,希望在执行派生类的构造函数时,使派生类的数据成员和基类的数据成员同时都被初始化。解决这个问题的思路是:在执行派生类的构造函数时,调用基类的构造函数。,例11.5 简单的派生类的构造函数。#include#includeusing namespace std;class Student/声明基类Student public:Student(int n,string nam,char s)/基类构造函数 num=n;name=nam;sex=s;Student()/基类析构函数protected:/保护部分 in

25、t num;string name;char sex;,11.5.1 简单的派生类的构造函数,class Student1:public Student public: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:addrendl;Student1()private:,调用基类构造函数,派生类新增的数据成员

26、初始化,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;,运行结果为num:10010name:Wang-lisex:fage:19address:115 Beijing Road,Shanghainum:10011name:Zhang-funsex:mage:21ad

27、dress:213 Shanghai Road,Beijing,派生类构造函数的一般形式为:派生类构造函数名(总参数表列):基类构造函数名(参数表列)派生类中新增数据成员初始化语句例如:,派生类构造函数在类外定义,而在类体中函数的声明:Student1(int n,string nam,char s,int a,string ad);在类的外面定义派生类构造函数:Student1Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s)age=a;addr=ad;,注意:在类中对派生类构造函数声明时,不包括基类构造函数名

28、及其参数表列(即Student(n,nam,s))。调用基类构造函数时的实参是从派生类构造函数总参数表中得到的,也可以不从派生类构造函数总参数表中传递过来,而直接使用常量或全局变量。例:Student1(string nam,char s,int a,string ad):Student(10010,nam,s)age=a;addr=ad;,常量,利用初始化表对构造函数的数据成员初始化 Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s),age(a),addr(ad)在建立一个派生类对象时,执行构造函数的顺序是:

29、派生类构造函数先调用基类构造函数;再执行派生类构造函数本身(即派生类构造函数的函数体)。在派生类对象释放时,执行析构函数的顺序是:先执行派生类析构函数;再执行其基类析构函数。,类的数据成员中还可以包含类对象。例:Student s1;/s1是Student类的对象s1就是类对象中的内嵌对象,称为子对象(subobject),即对象中的对象。,11.5.2 有子对象的派生类的构造函数,例11.6 包含子对象的派生类的构造函数。#include#include using namespace std;class Student public:Student(int n,string nam)num

30、=n;name=nam;void display()coutnum:numendlname:nameendl;protected:int num;string name;class Student1:public Student,public: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();coutage:ageendl;coutaddre

31、ss:addrendl;void show_monitor()coutendlClass monitor is:endl;monitor.display();/调用基类成员函数,基类参数,子类参数,派生类参数,1、基类构造函数,2、子类构造函数,3、派生类构造函数,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

32、();/输出子对象的数据return 0;,运行时的输出如下:This student is:num:10010name:Wang-liage:19address:115 Beijing Road,Shanghai Class monitor is:num:10001name:Li-sun,定义派生类构造函数的一般形式为:派生类构造函数名(总参数表列):基类构造函数名(参数表列),子对象名(参数表列)派生类中新增数据成员初始化语句总参数表列中的参数,应当包括基类构造函数、子对象的参数表列中的参数和派生类中新增数据成员的参数。基类构造函数和子对象的次序可以是任意的。派生类构造函数的任务:对基类、

33、子对象和派生类数据成员做初始化。,执行派生类构造函数的顺序是:调用基类构造函数,对基类数据成员初始化;调用子对象构造函数,对子对象数据成员初始化;再执行派生类构造函数本身,对派生类数据成员初始化。,一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构。,11.5.3 多层派生时的构造函数,例11.7 多级派生情况下派生类的构造函数。#include#includeusing namespace std;class Student public:Student(int n,string nam)num=n;name=nam;void display()coutnum:nume

34、ndl;coutname:nameendl;protected:int num;string name;,class Student1:public Student public:Student1(int n,string nam,int a):Student(n,nam)age=a;void show()display();coutage:ageendl;private:int age;class Student2:public Student1/声明间接公用派生类 public:,/下面是间接派生类构造函数 Student2(int n,string nam,int a,int s):St

35、udent1(n,nam,a)score=s;void show_all()show();/输出num、name和age coutscore:scoreendl;private:int score;int main()Student2 stud(10010,Li,17,89);stud.show_all();return 0;,运行时的输出如下:num:10010name:Liage:17score:89,其派生关系如下图。,基类和两个派生类的构造函数的写法:基类的构造函数首部:Student(int n,string nam)派生类Student1的构造函数首部:Student1(int n

36、,string nam,int a):Student(n,nam)派生类Student2的构造函数首部:Student2(int n,string nam,int a,int s):Student1(n,nam,a)初始化的顺序是:先初始化基类的数据成员num和name。再初始化Student1的数据成员age。最后再初始化Student2的数据成员score。,使用派生类构造函数时,有以下特殊形式:当不需要对派生类新增的成员进行任何初始化操作时,派生类构造函数的函数体可以为空,即构造函数是空函数,如:Student1(int n,string nam,int n1,string nam1):

37、Student(n,nam),monitor(n1,nam1)如果基类中没有定义构造函数,或定义了没有参数的构造函数,那么在定义派生类构造函数时可不写基类构造函数。调用派生类构造函数时系统会自动首先调用基类的默认构造函数。,11.5.4 派生类构造函数的特殊形式,如果基类和子对象类型都没有定义带参数的构造函数,而且也不需对派生类自己的数据成员初始化,则可以不必显式地定义派生类构造函数。在建立派生类对象时,系统会自动调用派生类的默认构造函数,并在执行派生类默认构造函数的过程中,调用基类的默认构造函数和子对象类型默认构造函数。,如果在基类中既定义无参的构造函数,又定义了有参的构造函数(构造函数重载

38、),则在定义派生类构造函数时,既可以包含基类构造函数及其参数,也可以不包含基类构造函数。在调用派生类构造函数时,根据构造函数的内容决定调用基类的有参的构造函数还是无参的构造函数。,对派生类中所增加的成员进行清理工作,需要定义自己的析构函数。基类的清理工作仍然由基类的析构函数负责。在执行派生类的析构函数时,系统会自动调用基类的析构函数和子对象的析构函数,对基类和子对象进行清理。调用的顺序与构造函数正好相反:先执行派生类自己的析构函数;然后调用子对象的析构函数;最后调用基类的析构函数。,11.5.5 派生类的析构函数,多重继承:派生类同时继承多个基类。,11.6 多重继承,11.6.1 声明多重继

39、承的方法,如果已声明了类A、类B和类C,可以声明多重继承的派生类D:class D:public A,private B,protected C类D新增加的成员,D是多重继承的派生类,它以公用继承方式继承A类,以私有继承方式继承B类,以保护继承方式继承C类。D按不同的继承方式的规则继承A,B,C的属性,确定各基类的成员在派生类中的访问权限。,多重继承派生类的构造函数形式。如:,11.6.2 多重继承派生类的构造函数,派生类构造函数名(总参数表列):基类1构造函数(参数表列),基类2构造函数(参数表列),基类3构造函数(参数表列)派生类中新增数成员据成员初始化语句,各基类的排列顺序任意。派生类构

40、造函数的执行顺序同样为:先调用基类的构造函数,再执行派生类构造函数的函数体。调用基类构造函数的顺序是按照声明派生类时基类出现的顺序。,例11.8 声明一个教师(Teacher)类和一个学生(Student)类,用多重继承的方式声明一个研究生(Graduate)派生类。教师类中包括数据成员name(姓名)、age(年龄)、title(职称)。学生类中包括数据成员name1(姓名)、age(性别)、score(成绩)。在定义派生类对象时给出初始化的数据,然后输出这些数据。,#include#include using namespace std;class Teacher public:Teach

41、er(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 public:Student(char nam,char s,float sco)strcpy(name1,nam);sex=s;score=sco;void display1()coutname:name1endl;coutsex:se

42、xendl;coutscore:scoreendl;protected:char name18;char sex;float score;/成绩;,class Graduate:public Teacher,public Student public:Graduate(char 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

43、;coutscore:scoreendl;couttitle:titleendl;coutwages:wageendl;private:float wage;/工资;,如果Teacher和Student类中都是name,会出现二义性。正确作法可加限定:Teacher:name,int main()Graduate grad1(“Wang-li”,24,f,“assistant”,89.5,1234.5);grad1.show();return 0;在两个基类中分别用name和name1来代表姓名,其实这是同一个人的名字,从Graduate类的构造函数中可以看到总参数表中的参数nam分别传递给两

44、个基类的构造函数,作为基类构造函数的实参。,程序运行结果如下:name:Wang-li age:24sex:fscore:89.5 title:assistancewages:1234.5,在多重继承中,当多个基类中包含同名成员时,它们在派生类中就会出现名冲突问题。例:,11.6.3 多重继承引起的二义性问题,class Apublic:int a;void display();class Bpublic:int a;void display();,class C:public A,public Bpublic:int b;void show();void main()C c1;c1.a=3;

45、c1.display();,同名冲突,(1)两个基类有同名成员。如图所示。,class Apublic:int a;void display();class Bpublic:int a;void display();class C:public A,public Bpublic:int b;void show();,void main()C c1;c1.a=3;/二义性 c1.display();/二义性,void main()C c1;c1.A:a=3;/正确 c1.A:display();/正确,void show()A:a=3;/不必加对象名 A:display();/不必加对象名,两个

46、基类有同名成员的表示:,(2)两个基类和派生类三者都有同名成员。将上面的C类声明改为class C:public A,public Bint a;void display();,void main()C c1;c1.a=3;/访问C中的成员c1.display();/访问C中的成员,void main()C c1;c1.A:a=3;/访问A中的成员c1.A:display();/访问A中的成员,基类中的同名成员被覆盖,规则:基类的同名成员在派生类中被屏蔽,成为“不可见”的,或者说,派生类新增加的同名成员覆盖了基类中的同名成员。注意:不同的成员函数,只有在函数名和参数个数相同、类型相匹配的情况下

47、才发生同名覆盖如果只有函数名相同而参数不同,不会发生同名覆盖,而属于函数重载。,(3)如果类A和类B是从同一个基类派生的,如图所示。,class Npublic:int a;void display()coutA:a=”aendl;class A:public Npublic:int a1;class B:public Npublic:int a2;,class C:public A,public Bpublic:int a3;void show()couta3endl;int main()C c1;,派生类C中成员的情况。,void main()C c1;c1.A:a=3;c1.A:disp

48、lay();/访问类N的派生类A中的基类成员,void main()C c1;c1.a=3;/二义性c1.display();/二义性,void main()C c1;c1.N:a=3;/二义性c1.N:display();/二义性,1.虚基类的作用C+提供虚基类(virtual base class)的方法,使得在继承间接共同基类时只保留一份成员。,11.6.4 虚基类,例:将类A声明为虚基类的方法如下:class A;class B:virtual public A/类A是B的虚基类;class C:virtual public A/类A是C的虚基类;,声明虚基类的一般形式为:class

49、派生类名:virtual 继承方式 基类名声明为虚基类后,基类通过多条派生路径被一个派生类继承时,该派生类只继承该基类一次。,在派生类B和C中作了上面的虚基类声明后,派生类D中的成员如下图所示。,注意:为了保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类。否则仍然会出现对基类的多次继承。见下图,2.虚基类的初始化如果在虚基类中定义了带参数的构造函数,而且没有定义默认构造函数,则在其所有派生类(包括直接派生或间接派生的派生类)中,通过构造函数的初始化表对虚基类进行初始化。例:,class A A(int i);class B:virtual public A/A作为B的

50、虚基类 B(int n):A(n)/在初始化表中对虚基类初始化;class C:virtual public A C(int n):A(n)/在初始化表中对虚基类初始化;class D:public B,public C D(int n):A(n),B(n),C(n)/在初始化表中对所有基类初始化;,注意:在定义类D的构造函数时,与以往使用的方法有所不同。规定:在最后的派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化。C+编译系统只执行最后的派生类对虚基类的构造函数的调用,而忽略虚基类的其他派生类(如类B和类C)对虚基类的构造函数的调用,这就保证了虚基类的数据成员不会被多次初始

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号