作者:gzshun. 原创作品,转载请标明出处!
来源:http://blog.csdn.net/gzshun
本文主要是讨论类的多继承,多继承的方式可使派生类具有多个基类的特性。以下是一个继承关系,C从A和B基类中派生出来,在派生类C中,包含了基类A与基类B的成员,还有C类自己的成员。
在上述关系图中,可以看到,类继承的结构很清晰,但在很多时候,有可能有以下继承关系:
在这幅类的继承关系图中可以看到,B1和B2分别继承于A,再由B1和B2派生出C,这关系看起来很简单,但在内部,有点麻烦?
产生二义性。
A派生出B1和B2,所以B1和B2中分别包含A的成员,再由B1和B2派生出C,此时C包含了B1和B2类的成员,所以C中总共有2个A成员。这时候麻烦了,如何要对C类中B1父类中的A类成员修改,或者是对C类中的B2父类中的A类成员修改呢?这有点绕口,C++提供了一种方法是通过作用域来指定,可以参考前一篇博文《C++学习-继承中的作用域(10)》
这里给一个简单的例子:
执行结果:
B1::mA = 30
B2::mA = 50
mB1 = 20
mB2 = 40
mC = 10
从这个例子可以看到,使用作用域运算符"::"来消除二义性,这样就能巧妙地避免那个棘手的问题。不过在类C中,包含了2个A的部分,有点浪费空间。当然C++是非常伟大的,还有另一种更好的办法,就是使用虚基类,也可以称为虚继承。
虚基类的作用:使用虚基类能够在多重派生的过程中,使公有的基类在派生类中只有一个拷贝,这样就能解决上述二义性的错误。如果使用虚基类,那么以上类C当中也就只有1个A的部分。在虚基类的使用过程中,还有一个非常重要的特性,看例子便可发现。
看例子:
执行结果:
B1::mA = 0
B2::mA = 0
mA = 0
mB1 = 20
mB2 = 40
mC = 10
B1::mA = 163
B2::mA = 163
mA = 163
mB1 = 20
mB2 = 40
mC = 10
对比一下这两个例子,差别很小,将作用域的调用方式给去掉了。在这个例子当中,使用了virtual方式继承了基类A,所以在B1和B2中,对类A只有一个拷贝,若使用virtual方式继承,不管派生多少派生类,类A永远只有一个拷贝。对mA进行修改,从B1或B2调用mA,都是调用同一个副本,从结果可以看出这一结论。
重要:
虚基类的构造函数的调用方法与一般基类的构造函数的调用方法是不同的。在这个例子中,编译器没有调用B1或者B2的构造函数来调用基类A的构造函数,因为在虚继承过程中,基类A只有一个拷贝,所以编译器无法确定应该由类B1或者类B2的构造函数来调用基类A的构造函数,所以此时调用的是基类A的默认构造函数,所以刚开始mA的结果为0,是基类A的默认构造函数设置的默认值。
C++规定,由虚基类经过一次或者多次派生出来的派生类,在其每一个派生类的构造函数的成员初始化列表中必须给出对虚基类的构造函数的调用,如果未列出,则调用虚基类的默认构造函数。
在本例当中,在执行B1和B2的构造函数时都不调用虚基类A的构造函数,而是在类C中的构造函数直接调用虚基类A的默认构造函数。(因为编译器无法确定)
再看一个与上面几乎是一样的例子,只有一个区别,就是在类C的初始化列表中显示的调用虚基类A的构造函数,如下:
执行结果:
B1::mA = 20
B2::mA = 20
mA = 20
mB1 = 20
mB2 = 40
mC = 10
B1::mA = 163
B2::mA = 163
mA = 163
mB1 = 20
mB2 = 40
mC = 10
唯一的区别就是这行代码:
C(int x, int a, int b, int c, int d) : A(a), B1(a, b), B2(c, d), mC(x) {}
在这里显示地调用虚基类A的构造函数,并传入初始值,所以第一次打印mA的值不是0,而是20。
虚基类有这些特性,务必记住,看例子便可知分晓,OVER!
分享到:
相关推荐
C++实例关于多继承和虚基类PPT多继承和虚基类PPT
1, 设计一个人员基类person类,包括描述基本信息的数据成员,提供基本操作的函数成员以及析构函数和不同形式的构造函数
c++多重继承与虚基类的ppt 讲细致 易懂
多继承下的派生类构造函数必须同时负责该派生类的所有基类构造函数的参数传递。且构造函数和析构函数的调用顺序和单继承是一样的,先调用基类构造函数,再调用对象成员的构造函数,最后调用派生类的构造函数。那么...
从bicycle和motorcar派生出motorcycle,观察虚基类对继承的影响。 定义一个motorcycle的对象,分别调用run()和stop(),观察构造/析构函数的调用情况。 注意:构造函数和析构函数中均为cout语句,说明哪个构造/析构...
C++ 内存布局虚继承 ---Empty virtual base classs (空虚基类).doc
利用C++计算正方形,矩形,三角形圆形的面积,包含了虚函数,继承,多态相关的基础知识,这是一个示例程序力求简单易懂。代码采用VC6.0建立工程。
NULL 博文链接:https://jacky-dai.iteye.com/blog/2305501
虚基类与虚函数 虚基类的概念 ... 在C++语言中,一个类不能被多次说明为一个派生类的直接基类,但可以不止一次地成为间接基类。这就导致了一些问题。为了方便 说明,先介绍多继承的“类格”表示法。
本文分两部分即继承和虚函数与多态性,本文第一部分详细讲解了继承时的构造函数和析构函数的问题,父类与子类的 同名变量和函数问题,最后介绍了多重继承与虚基类。本文第二部分重点介绍了虚函数与多态性的问题,...
定义一个Person 类,结构如下图,为该类添加输入输出流运算符重载。Person 类以Public方式派生出一个Teacher类,数据成员包括:int gh(工号);char* title(职称),为该类添加输入输出流运算符重载,完成有参、无参、...
C++继承与派生虚基类[参照].pdf
在校学习C++的时候,实验课的题目。学生类,留学生类、研究生类、留学研究生类,包含了虚基类创建、多个以及连续的继承派生,在主函数中调用实现各类内容。
c++的高校员工管理系统,使用类、继承还有文件的相关的知识。 功能:录入,查找,修改,删除,保存信息。
可见性继承比较简单,而虚拟继承对学习c++的难度较大。 首先,虚拟继承与普通继承的区别有: 假设derived 继承自base类,那么derived与base是一种“is a”的关系,即derived类是base类,而反之错误; ...
简单例子展示虚函数展现的多态特性,更改一处注释就能对比基类是否是虚函数带来的变化
子对象重叠,虚基类,开销,向上映射,避免MI,修复接口
虚基类的简单应用举例,分别把不同类的声明放在不同的头文件中,把不同类的实现放在不同的源文件中,把类的声明和成员函数的定义进行分离,初步实现了C++在实际工作中的编程思想,信息屏蔽。
在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数。下面就是一个例子:
今天重温C++的知识,当看到虚基类这点的时候,那时候也没有太过追究,就是知道虚基类是消除了类继承之间的二义性问题而已,可是很是好奇,它是怎么消除的,内存布局是怎么分配的呢?于是就深入研究了一下,具体的...