虚基类与虚函数.ppt
《虚基类与虚函数.ppt》由会员分享,可在线阅读,更多相关《虚基类与虚函数.ppt(50页珍藏版)》请在三一办公上搜索。
1、2023/10/22,1,5.2.2 虚基类,1.虚基类的概念 在C+语言中,一个类不能被多次说明为一个派生类的直接基类,但可以不止一次地成为间接基类。这就导致了一些问题。为了方便 说明,先介绍多继承的“类格”表示法。派生类及其基类可用一有向无环图(DAG)表示,其中的箭头表示“由派生而来”。类的DAG常称为一个“类格”。复杂类格画出来通常更容易理解。例如:,例 5-19 class L public:int next;class A:public L;class B:public L;class C:public A,public B public:void f()next=0;,这时,ne
2、xt有两个赋值语句next=0;具有二义性,它是将A:next置为零,还是将B:next置为零,或者将两者都置为0,需要在函数f()中被显式的说明.,2023/10/22,3,如果希望间接基类L与其派生类的关系是如下图,C+语言提供了这种描述手段。它将L说明为A和B的虚基类。,2023/10/22,4,当在多条继承路径上有一个公共的基类,在这些路径中的某几条路经汇合处,这个公共基类就会产生多个实例。如果只想保存这个基类的一个实例,可以将这个公共基类说明为虚拟基类或称虚基类。它仅是简单地将关键字virtual加到基类的描述上,例如改写上述例子为例5-20,例 5-20 class L publi
3、c:int next;class A:virtual public L;class B:virtual public L;class C:public A,public B public:void f()next=0;,这时C类对象中只有L的一个复制,因而函数C:f()中的语句next=0;没有二义性。对于类C而言,L类是B类的虚基类,而是类A的真基类;但对于类B而言,L类还是B类的真基类。例 5-21,或class A:public virtual L,或class A:public virtual,class L public:int next;class A:virtual public
4、 L;class B:virtual public L;class C:public B,public A public:void f()next=0;,此例中,对于类C而言,L类是A类的虚基类,而是类B的真基类。,派生时,A,B的顺序变了,2023/10/22,7,一个派生类的对象的地址可以直接赋给虚基类的指针,例如:C obj;L*ptr=将产生编译错误。,2023/10/22,8,2.虚基类对象的初始化 虚基类的初始化与多继承的初始化在语法上是一样的,但隐含的构造函数的调用次序有点差别。虚基类构造函数的调用次序是这样规定的:1.虚基类的构造函数在非虚基类之前调用。2.若同一层次中包含多个
5、虚基类,虚基类构造函数按它们说明的次序调用。3.若虚基类由非虚基类派生,则遵守先调用基类构造函数,再调用派生类构造函数的规则。,2023/10/22,9,例如:class X:public Y,virtual public Z X one;将产生如下调用次序:Z()Y()X()这里Z是X的虚基类,故先调用Z的构造函数,再调用Y的构造函数,最后才调用派生类X自己的构造函数。例 5-22,#include iostream.h class base public:base()coutBaseendl;class base2 public:base2()coutBase2endl;class lev
6、el1:public base2,virtual public base public:level1()coutlevel1endl;class level2:public base2,virtual public base public:level2()coutlevel2endl;class toplevel:public level1,virtual public level2 public:toplevel()couttoplevelendl;,toplevel view;void main(),当建立对象view时,将产生如下调用次序:level2()level1()toplevel
7、()而level2()要求:base()base2()level2()level1()要求 base2()level1()toplevel()要求 toplevel(),所以,构造函数的调用顺序为:base()base2()level2()base2()level1()toplevel(),例5-23 class base;class base2;class level1:public base2,virtual public base;class level2:public base2,virtual public base;class toplevel:virtual public lev
8、el1,public level2;toplevel view;,level1():base()base2()level1()level2():base2()level2()toplevel():toplevel(),当建立对象view时,将产生如下调用次序:,此例中,对于toplevel的而言,base是level2的虚基类,2023/10/22,12,例 5-24 class B;class X:virtual public B;class Y:virtual public B;class Z:public B;class AA:public X,public Y,public Z;,这里
9、AA具有两个B类的子对象:Z的B和x与Y共享的虚拟的B。,class V public:int V;class A public:int a;class B:public A,virtual public V;class C:public A,Virtual public V;class D:public B,public C public:void f();,void D:f()v+;a+;,例 5-25 虚基类和非虚基类的不同。,在D中仅仅一个v,错误,具有二义性,在D中有两个a,调用次序:B():V()A()B()C():A()C()D():D(),2023/10/22,14,5.3 虚
10、函数与多态性,对于普通成员函数的重载,可表达为下面的方式:1)在同一个类中重载 2)在不同类中重载 3)基类的成员函数在派生类中重载 因此,重载函数的访问是在编译时区分的,有以下三种方法:,2023/10/22,15,1.根据参数的特征加以区分,例如:Show(int,char)与Show(char*,float)不是同一函数,编译能区分。2.使用“:”加以区分,例如:Circle:Show有别于Point:Show 3.根据类对象加以区分。ACircle.Show()调用Circle:Show()APoint.Show()调用Point:Show()这里ACircle和APoint分别是Ci
11、rcle和Point的对象。,例 5-26#include class A public:void fun()cout“In A”endl;class B:public A public:void fun()cout“In B”endl;class C:public B public:void fun()cout“In C”endl;,void main()C Cobj;Cobj.fun();Cobj.B:fun();Cobj.A:fun();A,5.3.1 基类对象的指针指向派生类对象,指向基类和派生类的指针变量是相关的,假设B_class是基类,D_class是从B_class公有派生出来
12、的派生类,任何被说明为指向B_class的指针也可以指向D_class。例如:,利用p,可以访问从基类B_class继承的成员,但D_class自己定义的成员,p不能访问。例如:例5-27,指向类型B_class的对象的指针,类型B_class的对象,类型D_class的对象,p指向类型D_class的对象,它是 B_class 的派生类,p指向类型B_class的对象,B_class*p;B_class B_ob;D_class D_ob;p=,#include#include class B_classchar name80;public:void put_name(char*s)strc
13、py(name,s);void show_name()coutnamen;,main()B_class*p;B_class B_ob;D_class*dp;D_class D_ob;p=,错误,错误,该程序输出:Thomas Edison Albert Einstein 555555_1234 555555_1234,class D_class:public B_class char phone_num80;public:void put_phone(char*num)strcpy(phone_num,num);void show_phone()coutphone_numn;,基类指针指向派生
14、类类对象,只能访问基类成员,派生类指针指向派生类类对象,访问所有成员,基类指针,派生类指针,1.可以用一个指向基类的指针指向其公有派生类的对象。但是相反却不正确,即不能用指向派生类的指针指向一个基类的对象。2.希望用基类指针访问其公有派生类的特定成员,必须将基类指针用显式类型转换为派生类指针。例如:(D_class*)p)-show_phone();,5.3.2 虚函数,例 5-28#include class Base protected:int x;public:Base(int a)x=a;void who()cout“base”x“n”;,class Second_d:public B
15、ase public:Second_d(int a):Base(a)void who()cout“Second derivation”x“n”;,class First_d:public Base public:First_d(int a):Base(a)void who()cout“First derivation”x“n”;,1.虚函数的概念,void main()Base*p;Base base_obj(1);First_d first_obj(2);Second_d second_obj(3);p=,该程序输出:base 1base 2base 3First derivation 2S
16、econd derivation 3,p-who(),指向基类的指针p,不管是指向基类的对象base_obj还是指向派生的对象first_obj和second_obj,p-who()调用的都是基类定义的 who()的版本.必须显式地用 first_obj.who();和 second_obj.who();才能调用类first_d和类second_d中定义的who()的版本。其本质的原因在于普通成员函数的调用是在编译时静态区分。,2023/10/22,22,如果随着p所指向的对象的不同pwho()能调用不同类中who()版本,这样就可以用一个界面p-who()访问多个实现版本:Base中的who
17、(),First_d 中的 who(),以及Second_d中的who(),这在编程时非常有用。实际上,这表达了一种动态的性质,函数调用p-who()依赖于运行时p所指向的对象。虚函数提供的就是这种解释机制。如果在base中将成员函数who()说明为虚函数,则修改上述程序为例5-29,虚函数是在基类中被冠以virtual的成员函数,它提供了一种接口界面。虚函数可以在一个或多个派生类中被重新定义,但要求在派生类中 重新定义时,虚函数的函数原型,包括返回类型,函数名,参数个数,参数类型的顺序,必须完全相同。,class First_d:public Base public:First_d(int
18、a):Base(a)void who()“First derivation“x“n”;,#include class Base protected:int x;public:Base(int a)x=a;virtual void who()cout“base”x“n”;,class Second_d:public Base public:Second_d(int a):Base(a)void who()“Second derivation“x“n”;,void main()Base*p;Base base_obj(1);First_d first_obj(2);Second_d second_
19、obj(3);p=,程序输出:base 1 First derivation 2 Second derivation 3 First derivation 2 Second derivation 3,基类的虚函数who()定义了一种接口,在派生类中此接口定义了不同的实现版本,由于虚函数的解释机制,实现了“单界面,多实现版本”的思想。这种在运行时刻将函数界面与函数的不同实现版本进行匹配的过程,称为晚期匹配,也称为运行时的多态性。,p-who(),基类函数f具有虚特性的条件是:1)在基类中,将该函数说明为virtual函数。2)定义基类的公有派生类。3)在基类的公有派生类中原型一致地重载该虚函数。
20、4)定义指向基类的指针变量,它指向基类的公有派生类的对象。例 5-30,void main()derived d;base*bp=,class base public:virtual void vf1();virtual void vf2();virtual void vf3();void f();class derived:public base public:void vf1();void vf2(int);char vf3();void f();;,错误,仅返回类型不同,具有虚特性,一般函数重载,参数不同,虚特性丢失,一般的函数重载,非虚函数的重载,例 5-31#include clas
21、s figure protected:double x,y;public:void set_dim(double i,double j=0)x=i;y=j;virtual void show_area()cout“No area computation defined”;cout“for this class.n”;,class triangle:public figure public:void show_area()cout“Triangle with high”;coutx“and base”y;cout“has an area of”;coutx*0.5*y“n”;,class squ
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 虚基类 函数

链接地址:https://www.31ppt.com/p-6375729.html