教学第四章派生类与继承课件2_第1页
教学第四章派生类与继承课件2_第2页
教学第四章派生类与继承课件2_第3页
教学第四章派生类与继承课件2_第4页
教学第四章派生类与继承课件2_第5页
已阅读5页,还剩155页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第四章派生类与继承(2)第四章派生类与继承(2)表4.1(1)基类中的私有成员无论何种继承方式,派生类均不可直接访问(2)基类中的共有成员根据继承方式而改变(3)基类中的保护成员共有/保护继承时不变,私有继承时改变4.1.3基类成员在派生类中的访问属性表4.14.1.3基类成员在派生类中的访问属性4.1.4派生类对基类成员的访问规则访问形式:内部访问由派生类新增成员对基类继承来的成员进行访问.对象访问在派生类外部,通过派生类对象对基类继承来的成员进行访问.4.1.4派生类对基类成员的访问规则访问形式:1.私有继承的访问规则基类的public和protected成员被继承后,变成派生类的私有成员.派生类其他成员可直接访问(内部可访问)外部通过派生类对象无法访问1.私有继承的访问规则基类的public和protec例:4.1private:Xpublic:setx(intx)showx()private:Ypublic:setxy(intn,intm)showxy()basederive私有派生voidshowxy(){cout<<x;cout<<y<<endl;}例:4.1private:Xprivate:Y例4.2protected:apublic:seta(intsa)showa()protected:bpublic:seta(intsa,intsb)showab()protected:cpublic:seta(intsa,intsb,intsc)showabc()basederive1derive2私有派生私有派生例4.2protected:aprotected:b1.私有继承的访问规则表4.2内部可访问基类的public和protected成员外部对象对基类成员均不能访问。1.私有继承的访问规则表4.22.公有继承的访问规则公有继承基类所有成员(不变)内部可访问:基类的public和protected外部可访问:基类的public基类的private内外都不能直接访问;2.公有继承的访问规则公有继承基类所有成员(不变)例4.3private:xprotected:ypublic:setxy(…)showxy()private

:zpublic:setxyz(…)showxyz()basederive公有派生voidsetxyz(intm,intn,intj){setxy(m,n);Z=j;}voidshowxyz(){cout<<x<<endl;cout<<y<<endl;cout<<z<<endl;}例4.3private:xprivate:z2.公有继承的访问规则表4.3内部可访问基类的public和protected成员外部对象可访问:基类的public基类的private内外都不能直接访问;2.公有继承的访问规则表4.33.保护继承的访问规则基类的public和protected成员,通过保护继承作为派生类中的protected成员基类的private成员(不变),派生类无论内部还是外部均不可直接访问。3.保护继承的访问规则基类的public和protected例4.4private:xprotected:ypublic:zsetx(…)getx()basederive保护继承private

:mprotected:npublic:psetall(…)show()voidsetall(….){

x=a;//setx(a);y=b;z=c;…..}例4.4private:xbase3.保护继承的访问规则表4.4内部可访问:基类的public和protected成员外部对象均不可直接访问基类成员。3.保护继承的访问规则表4.44.2派生类的构造函数和析构函数基类都有显式或隐式的构造函数和析构函数当创建一个派生类对象时,如何调用基类的构造函数对基类数据初始化,以及在撤消派生类对象时,又如何调用基类的析构函数来对基类对象的数据成员进行善后处理?第四章派生类与继承课件24.2.1派生类构造函数和析构函数的执行顺序

通常情况下,当创建派生类对象时:当撤消派生类对象时,顺序相反执行基类的构造函数执行派生类的构造函数执行派生类的析构函数执行基类的析构函数执行基类的构造函数执行派生类的构造函数执行派生类的析构函数执第四章派生类与继承课件2第四章派生类与继承课件24.2.2派生类构造函数和析构函数的构造规则

当基类的构造函数没有参数,或没有显式定义构造函数时,派生类可以不向基类传递参数,甚至可以不定义构造函数。例4.5的程序就是由于基类的构造函数没有参数,所以派生类没有向基类传递参数。派生类不能继承基类中的构造函数和析构函数。当基类合有带参数的构造函数时,派生类必须定义构造函数.以提供把参数传递给基类构造函数的途径。在C++中,派生类构造函数的一般格式为:

派生类构造函数名(参数表):基类构造函数名(参数表)4.2.2派生类构造函数和析构函数的构造规则第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2当派生类中含有对象成员时,构造函数的一般形式:派生类构造函数名(参数表):基类构造函数名(参数表)、对象成员名1(参数表),…、对象成员名n(参数表)在定义派生类对象时,构造函数的执行顺序:基类的构造函数对象成员的构造函数派生类的构造函数撤消对象时,析构函数的调用顺序与构造函数的调用顺序正好相反。当派生类中含有对象成员时,构造函数的一般形式:第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2(1)当基类构造函数不带参数时,派生类不一定需要定义构造函数,然而当基类的构造函数那怕只带有一个参数,它所有的派生类都必须定义构造函数,甚至所定义的派生类构造函数的函数体可能为空,仅仅起参数的传递作用。derived(intn):base(n){j=0;}说明(1)当基类构造函数不带参数时,派生类不一定需要定义构造函数说明(2)若基类使用缺省构造函数或不带参数的构造函数,则在派生类中定义构造函数时可略去“:基类构造函数名(参数表)”;此时若派生类也不需要构造函数,则可不定义构造函数。说明(2)若基类使用缺省构造函数或不带参数的构造函数,则在派(3)如果派生类的基类也是一个派生类,则每个派生类只需负责其直接基类的构造,依次上溯。(4)由于析构函数是不带参数的,在派生类中是否要定义析构函数与它所属的基类无关,故基类的析构函数不会因为派生类没有析构函数而得不到执行,它们各自是独立的。(3)如果派生类的基类也是一个派生类,则每个派生类只需负责其例题4.8Third(){e=0;}Third(intx,inty,intz):Second(x,y){e=z;}Second():First(1,1){c=0;d=0}Second(intx,inty):First(x+1,y+1){c=x;d=y}例题4.84.3调整基类成员在派生类中访问属性的其他方法4.3.1同名成员

Yobj; obj.f();

obj.x::f();在私有继承情况下,为了保证基类的一部分成员函数在派生类中也存在,必须在派生类中重新定义同名的成员。4.3调整基类成员在派生类中访问属性的其他方法4.3.14.3.2访问声明例题4.10(提出问题)C++提供访问声明的特殊机制,可个别调整基类的某些成员,使之在派生类中保持原来的访问属性。在派生类定义中加入访问声明:基类名::成员名;例题:4.11(解决问题)4.3.2访问声明例题4.10(提出问题)说明(1)数据成员也可以使用访问声明(2)访问声明不带类型和参数(3)基类私有成员不能使用访问声明(4)对于基类中重载函数名,访问声明对所有的同名函数都起作用。(慎重)说明(1)数据成员也可以使用访问声明

前面我们介绍的派生类只有一个基类,这种派生方法称为单基派生或单一继承。当一个派生类具有多个基类时,这种派生方法称为多基派生或多重继承。例如,用户界面所提供的窗口、滚动条、文本框以及多种类型的按钮,所有这些组件都是通过类来支持的,若把这些类中的两个类或多个类合并,则可产生一个新类,例如把窗口和滚动条合并起来产生一个可滚动的窗口,这个可滚动的窗口就是由多重继承得来的。4.4多重继承 前面我们介绍的派生类只有一个基类,这种派生方法称为

在c++中,声明具有两个以上基类的派生类与声明单基派生类的形式相似,只需将要继承的多个基类用逗号分隔即可,其声明的一般形式如下:4.3.1多重继承的声明在c++中,声明具有两个以上基类的派生类与声明单基派第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2

说明

对基类成员的访问必须是:

无二义的,必须想法消除二义性。说明

main(){

Zobj;

obj.f();}main()

假如定义类Z的对象obj,

zobj;则以下对函数f()的访问是二义的:

obj.f();二义性错误,不知调用的是类x的f(),还是类Y的f()使用成员名限定可以消除二义性,例如:

obj.X::f();调用类x的f()obj.Y::f();调月类Y的f()假如定义类Z的对象obj,

多重继承构造函数的定义形式与单继承构造函数约定义形式相似,只是n个基类的构造函数之间用“,”分隔。多重继承构造函数定义的一般形式如下:

派生类构造函数名(参数表):基类l构造函数名(参数表),基类2构造函数名(参数表),…,基类n构造函数名(参数表){//……….}4.3.2多重继承的构造函数与析构函数多重继承构造函数的定义形式与单继承构造函数约定义形式第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2

多重继承的构造函数的执行顺序与单继承构造函数的执行顺序相同:

先执行基类的构造函数

再执行对象成员的构造函数,

最后执行派生类构造函数。在多个基类之间,则严格按照派生类声明时从左到右的顺序来排列先后。而析构函数的执行顺序则刚好与构造函数的执行顺序相反。构造/析构函数执行顺序 多重继承的构造函数的执行顺序与单继承构造函数的1.为什么要引入虚基类

当引用派生类的成员时,首先在派生类自身的作用域中寻找这个成员,如果没有找到.则到它的基类中寻找。如果一个派生类是从多个基类派生出来的,而这些基类又有一个共同的基类,则在这个派生类中访问这个共同的基类中的成员时,可能会产生二义性。请看以下这段程序。虚基类1.为什么要引入虚基类虚基类protected:apublic:base(…)public:base1(…){cout<<a;}PublicBaseBase1public:base2(…){cout<<a;}PublicBase2Derivedpublic:derived(…){cout<<a;}PublicPublicprotected:aPublicBaseBase1Pu

上述程序中,类base是一个基类,从类base派生出类base1和类base2,这是两个单一继承;从类base1和类base2共同派生出类derived,这是一个多重继承。这是一个存在问题的程序,问题出在派生类derived的构造函数的定义上,它试图输出一个它有权访问的变量a,表面上看来这是合理的,但实际上它对a的访问存在二义性.即函数中的变量a的值可能是从basel的派生路径上来的,也有可能是从类base2的派生路径上来的,这里没有明确的说明。上述程序中,类base是一个基类,从类ba

虽然base1和base2是认同一个基类base派生而来的,但它们所对应的是基类base的不同拷贝。类derived是base1和base2的派生类,因此类base是类derived的间接基类,它有两个拷贝与类derived相对应,一个是basel派生路径上的拷贝,另一个是base2派生路径上的拷贝。当类derived要访问这个间接基类base时.必须指定要访问的是哪个路径上的base拷贝。这个例子中类之间的层次关系如图4.2所示。虽然base1和base2是认同一个基类base派第四章派生类与继承课件2

不难理解,如果在上例中类base只存在一个拷贝,那么对a的引用就不会产生二义性。在c++中,如果想使这个公共的基类只产生一个拷贝,则可以将这个基类说明为虚基类。这就要求从类base派生新类时,使用关键字virtual将类base说明为虚基类。下面的例子中用根基类重新定义例4.12中的类。2.虚基类的概念不难理解,如果在上例中类base只存在一个拷贝,第四章派生类与继承课件2第四章派生类与继承课件2

在上述程序中,从类base派生出类base1和类base2时,使用关键字virtual,把类base声明为base1和base2的虚基类。这样,从base1和base2派生出的类derived只有一个基类base,从而可以消除二义性。图4.3就是本例采用应基类后的类层次图。 在上述程序中,从类base派生出类base1和类base第四章派生类与继承课件2

虚基类的初始化与一般的多重继承的初始化在语法上是一样的,但构造函数的调用顺序不同。虚基类构造函数的调用顺序是这样规定的: (1)若同一层次中包含多个虚基类,这些虚基类的构造函数按对它们说明的先后次序调用。

3.虚基类的初始化虚基类的初始化与一般的多重继承的初始化在语法上是一

(2)若虚基类由非虚基类派生而来,则仍然先调用基类构造函数.再调用派生类的构造函数。

(3)若同一层次中同时包含虚基类和非虚基类,应先调用虚基类的构造函数,再调用非虚基类的构造函数,最后调用派生类构造函数(2)若虚基类由非虚基类派生而来,则仍然先调用基类构第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2

在上述程序中,base是一个虚基类,它只有一个带参数的构造函数,因此要求在派生类base1、base2和derived的构造函数的初始化表中都必须带有对base构造函数的调用。

如果base不是虚基类,在派生类derived的构造函数的初始化表中调用base的构造函数是错误的,但是当base是虚基类且只有带参数的构造函数时,就必须在类derived的构造函数的初始化表中调用类base的构造函数。因此,在derived构造函数的初始比表中,不仅含有对basel和base2构造函数的调用、还有对虚基类base构造函数的调用。 在上述程序中,base是一个虚基类,它只有一个带参数的构

不难看出,上述程序中虚基类base的构造函数只执行了一次。显然,当derived的构造函数调用了虚基类base的构造函数之后,类basel和类base2对base构造函数的调用被忽略了。这也是初始化虚基类和初始化非虚基类不同的地方。不难看出,上述程序中虚基类base的构造函数只执行说明

(1)关键字virtual与派生方式关键字(public或private)的先后顺序无关紧要,它只说明是“虚拟派生”。例如以下两个虚拟派生的声明是等价的。说明

(2)一个基类在作为某些派生类虚基类的同时.又作为另一些派生类的非虚基类,这种情况是允许存在的,例如:(2)一个基类在作为某些派生类虚基类的同时.又作为另第四章派生类与继承课件2

此例的类层次如图4.4所示。此例中,派生类AA由类X、类Y和类z派生而来。AA与它的间接基类B之间的对应关系是;类B既是x、Y继承路径上的一个虚基类,也是Z继承路径上酌一个非虚基类。此例的类层次如图4.4所示。此例中,派生类AA由类X、类4.5赋值兼容规则在需要基类对象的任何地方都可以使用公有派生类的对象来替代.(1)派生类对象给基类对象赋值(2)派生类对象初始化基类的引用(3)派生类对象地址赋值给指向基类的指针(4)派生类对象指针赋值给指向基类的指针4.5赋值兼容规则在需要基类对象的任何地方都可以使用例4.17Baseb1(11);Derivedd1(22);b1=d1;Derivedd2(33);

Base&b2=d2;Derivedd3(44);Base*b3=&d3;Derived*d4=newDerived(55);Base*b4=d4;b4->show();deleted4;例4.17Baseb1(11);说明(1)声明为指向基类对象的指针可指向其公有派生类对象,不允许指向私有派生的对象。(2)声明为指向派生类对象的指针不能指向基类的对象。(3)声明为指向基类对象的指针,当其指向公有派生类对象时,只能直接访问派生类中从基类继承来的成员说明(1)声明为指向基类对象的指针可指向其公有派生类对象,不将基类指针显式类型转换为派生类指针。((B*)ptr)->print2(

);正确public:voidprint1(){}public:print2(){}PublicABA*ptr;ptr->print2();将基类指针显式类型转换为派生类指针。PublicABA*4.6应用举例例4.18Data_recEmployeeStudentTeacherE_Strudent4.6应用举例例4.184.6应用举例例4.19locationpointcirclesXYshowhidemovetoshowhideexpand\contractmoveto4.6应用举例例4.19locationpointcirc第四章派生类与继承(2)第四章派生类与继承(2)表4.1(1)基类中的私有成员无论何种继承方式,派生类均不可直接访问(2)基类中的共有成员根据继承方式而改变(3)基类中的保护成员共有/保护继承时不变,私有继承时改变4.1.3基类成员在派生类中的访问属性表4.14.1.3基类成员在派生类中的访问属性4.1.4派生类对基类成员的访问规则访问形式:内部访问由派生类新增成员对基类继承来的成员进行访问.对象访问在派生类外部,通过派生类对象对基类继承来的成员进行访问.4.1.4派生类对基类成员的访问规则访问形式:1.私有继承的访问规则基类的public和protected成员被继承后,变成派生类的私有成员.派生类其他成员可直接访问(内部可访问)外部通过派生类对象无法访问1.私有继承的访问规则基类的public和protec例:4.1private:Xpublic:setx(intx)showx()private:Ypublic:setxy(intn,intm)showxy()basederive私有派生voidshowxy(){cout<<x;cout<<y<<endl;}例:4.1private:Xprivate:Y例4.2protected:apublic:seta(intsa)showa()protected:bpublic:seta(intsa,intsb)showab()protected:cpublic:seta(intsa,intsb,intsc)showabc()basederive1derive2私有派生私有派生例4.2protected:aprotected:b1.私有继承的访问规则表4.2内部可访问基类的public和protected成员外部对象对基类成员均不能访问。1.私有继承的访问规则表4.22.公有继承的访问规则公有继承基类所有成员(不变)内部可访问:基类的public和protected外部可访问:基类的public基类的private内外都不能直接访问;2.公有继承的访问规则公有继承基类所有成员(不变)例4.3private:xprotected:ypublic:setxy(…)showxy()private

:zpublic:setxyz(…)showxyz()basederive公有派生voidsetxyz(intm,intn,intj){setxy(m,n);Z=j;}voidshowxyz(){cout<<x<<endl;cout<<y<<endl;cout<<z<<endl;}例4.3private:xprivate:z2.公有继承的访问规则表4.3内部可访问基类的public和protected成员外部对象可访问:基类的public基类的private内外都不能直接访问;2.公有继承的访问规则表4.33.保护继承的访问规则基类的public和protected成员,通过保护继承作为派生类中的protected成员基类的private成员(不变),派生类无论内部还是外部均不可直接访问。3.保护继承的访问规则基类的public和protected例4.4private:xprotected:ypublic:zsetx(…)getx()basederive保护继承private

:mprotected:npublic:psetall(…)show()voidsetall(….){

x=a;//setx(a);y=b;z=c;…..}例4.4private:xbase3.保护继承的访问规则表4.4内部可访问:基类的public和protected成员外部对象均不可直接访问基类成员。3.保护继承的访问规则表4.44.2派生类的构造函数和析构函数基类都有显式或隐式的构造函数和析构函数当创建一个派生类对象时,如何调用基类的构造函数对基类数据初始化,以及在撤消派生类对象时,又如何调用基类的析构函数来对基类对象的数据成员进行善后处理?第四章派生类与继承课件24.2.1派生类构造函数和析构函数的执行顺序

通常情况下,当创建派生类对象时:当撤消派生类对象时,顺序相反执行基类的构造函数执行派生类的构造函数执行派生类的析构函数执行基类的析构函数执行基类的构造函数执行派生类的构造函数执行派生类的析构函数执第四章派生类与继承课件2第四章派生类与继承课件24.2.2派生类构造函数和析构函数的构造规则

当基类的构造函数没有参数,或没有显式定义构造函数时,派生类可以不向基类传递参数,甚至可以不定义构造函数。例4.5的程序就是由于基类的构造函数没有参数,所以派生类没有向基类传递参数。派生类不能继承基类中的构造函数和析构函数。当基类合有带参数的构造函数时,派生类必须定义构造函数.以提供把参数传递给基类构造函数的途径。在C++中,派生类构造函数的一般格式为:

派生类构造函数名(参数表):基类构造函数名(参数表)4.2.2派生类构造函数和析构函数的构造规则第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2当派生类中含有对象成员时,构造函数的一般形式:派生类构造函数名(参数表):基类构造函数名(参数表)、对象成员名1(参数表),…、对象成员名n(参数表)在定义派生类对象时,构造函数的执行顺序:基类的构造函数对象成员的构造函数派生类的构造函数撤消对象时,析构函数的调用顺序与构造函数的调用顺序正好相反。当派生类中含有对象成员时,构造函数的一般形式:第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2(1)当基类构造函数不带参数时,派生类不一定需要定义构造函数,然而当基类的构造函数那怕只带有一个参数,它所有的派生类都必须定义构造函数,甚至所定义的派生类构造函数的函数体可能为空,仅仅起参数的传递作用。derived(intn):base(n){j=0;}说明(1)当基类构造函数不带参数时,派生类不一定需要定义构造函数说明(2)若基类使用缺省构造函数或不带参数的构造函数,则在派生类中定义构造函数时可略去“:基类构造函数名(参数表)”;此时若派生类也不需要构造函数,则可不定义构造函数。说明(2)若基类使用缺省构造函数或不带参数的构造函数,则在派(3)如果派生类的基类也是一个派生类,则每个派生类只需负责其直接基类的构造,依次上溯。(4)由于析构函数是不带参数的,在派生类中是否要定义析构函数与它所属的基类无关,故基类的析构函数不会因为派生类没有析构函数而得不到执行,它们各自是独立的。(3)如果派生类的基类也是一个派生类,则每个派生类只需负责其例题4.8Third(){e=0;}Third(intx,inty,intz):Second(x,y){e=z;}Second():First(1,1){c=0;d=0}Second(intx,inty):First(x+1,y+1){c=x;d=y}例题4.84.3调整基类成员在派生类中访问属性的其他方法4.3.1同名成员

Yobj; obj.f();

obj.x::f();在私有继承情况下,为了保证基类的一部分成员函数在派生类中也存在,必须在派生类中重新定义同名的成员。4.3调整基类成员在派生类中访问属性的其他方法4.3.14.3.2访问声明例题4.10(提出问题)C++提供访问声明的特殊机制,可个别调整基类的某些成员,使之在派生类中保持原来的访问属性。在派生类定义中加入访问声明:基类名::成员名;例题:4.11(解决问题)4.3.2访问声明例题4.10(提出问题)说明(1)数据成员也可以使用访问声明(2)访问声明不带类型和参数(3)基类私有成员不能使用访问声明(4)对于基类中重载函数名,访问声明对所有的同名函数都起作用。(慎重)说明(1)数据成员也可以使用访问声明

前面我们介绍的派生类只有一个基类,这种派生方法称为单基派生或单一继承。当一个派生类具有多个基类时,这种派生方法称为多基派生或多重继承。例如,用户界面所提供的窗口、滚动条、文本框以及多种类型的按钮,所有这些组件都是通过类来支持的,若把这些类中的两个类或多个类合并,则可产生一个新类,例如把窗口和滚动条合并起来产生一个可滚动的窗口,这个可滚动的窗口就是由多重继承得来的。4.4多重继承 前面我们介绍的派生类只有一个基类,这种派生方法称为

在c++中,声明具有两个以上基类的派生类与声明单基派生类的形式相似,只需将要继承的多个基类用逗号分隔即可,其声明的一般形式如下:4.3.1多重继承的声明在c++中,声明具有两个以上基类的派生类与声明单基派第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2

说明

对基类成员的访问必须是:

无二义的,必须想法消除二义性。说明

main(){

Zobj;

obj.f();}main()

假如定义类Z的对象obj,

zobj;则以下对函数f()的访问是二义的:

obj.f();二义性错误,不知调用的是类x的f(),还是类Y的f()使用成员名限定可以消除二义性,例如:

obj.X::f();调用类x的f()obj.Y::f();调月类Y的f()假如定义类Z的对象obj,

多重继承构造函数的定义形式与单继承构造函数约定义形式相似,只是n个基类的构造函数之间用“,”分隔。多重继承构造函数定义的一般形式如下:

派生类构造函数名(参数表):基类l构造函数名(参数表),基类2构造函数名(参数表),…,基类n构造函数名(参数表){//……….}4.3.2多重继承的构造函数与析构函数多重继承构造函数的定义形式与单继承构造函数约定义形式第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2

多重继承的构造函数的执行顺序与单继承构造函数的执行顺序相同:

先执行基类的构造函数

再执行对象成员的构造函数,

最后执行派生类构造函数。在多个基类之间,则严格按照派生类声明时从左到右的顺序来排列先后。而析构函数的执行顺序则刚好与构造函数的执行顺序相反。构造/析构函数执行顺序 多重继承的构造函数的执行顺序与单继承构造函数的1.为什么要引入虚基类

当引用派生类的成员时,首先在派生类自身的作用域中寻找这个成员,如果没有找到.则到它的基类中寻找。如果一个派生类是从多个基类派生出来的,而这些基类又有一个共同的基类,则在这个派生类中访问这个共同的基类中的成员时,可能会产生二义性。请看以下这段程序。虚基类1.为什么要引入虚基类虚基类protected:apublic:base(…)public:base1(…){cout<<a;}PublicBaseBase1public:base2(…){cout<<a;}PublicBase2Derivedpublic:derived(…){cout<<a;}PublicPublicprotected:aPublicBaseBase1Pu

上述程序中,类base是一个基类,从类base派生出类base1和类base2,这是两个单一继承;从类base1和类base2共同派生出类derived,这是一个多重继承。这是一个存在问题的程序,问题出在派生类derived的构造函数的定义上,它试图输出一个它有权访问的变量a,表面上看来这是合理的,但实际上它对a的访问存在二义性.即函数中的变量a的值可能是从basel的派生路径上来的,也有可能是从类base2的派生路径上来的,这里没有明确的说明。上述程序中,类base是一个基类,从类ba

虽然base1和base2是认同一个基类base派生而来的,但它们所对应的是基类base的不同拷贝。类derived是base1和base2的派生类,因此类base是类derived的间接基类,它有两个拷贝与类derived相对应,一个是basel派生路径上的拷贝,另一个是base2派生路径上的拷贝。当类derived要访问这个间接基类base时.必须指定要访问的是哪个路径上的base拷贝。这个例子中类之间的层次关系如图4.2所示。虽然base1和base2是认同一个基类base派第四章派生类与继承课件2

不难理解,如果在上例中类base只存在一个拷贝,那么对a的引用就不会产生二义性。在c++中,如果想使这个公共的基类只产生一个拷贝,则可以将这个基类说明为虚基类。这就要求从类base派生新类时,使用关键字virtual将类base说明为虚基类。下面的例子中用根基类重新定义例4.12中的类。2.虚基类的概念不难理解,如果在上例中类base只存在一个拷贝,第四章派生类与继承课件2第四章派生类与继承课件2

在上述程序中,从类base派生出类base1和类base2时,使用关键字virtual,把类base声明为base1和base2的虚基类。这样,从base1和base2派生出的类derived只有一个基类base,从而可以消除二义性。图4.3就是本例采用应基类后的类层次图。 在上述程序中,从类base派生出类base1和类base第四章派生类与继承课件2

虚基类的初始化与一般的多重继承的初始化在语法上是一样的,但构造函数的调用顺序不同。虚基类构造函数的调用顺序是这样规定的: (1)若同一层次中包含多个虚基类,这些虚基类的构造函数按对它们说明的先后次序调用。

3.虚基类的初始化虚基类的初始化与一般的多重继承的初始化在语法上是一

(2)若虚基类由非虚基类派生而来,则仍然先调用基类构造函数.再调用派生类的构造函数。

(3)若同一层次中同时包含虚基类和非虚基类,应先调用虚基类的构造函数,再调用非虚基类的构造函数,最后调用派生类构造函数(2)若虚基类由非虚基类派生而来,则仍然先调用基类构第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2第四章派生类与继承课件2

在上述

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论