C++学习-多继承和虚基类

转载 2015年11月18日 10:29:21

本文主要是讨论类的多继承,多继承的方式可使派生类具有多个基类的特性。以下是一个继承关系,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。



相关文章推荐

c++中的 虚函数 纯虚函数 虚基类

原文出自http://blog.csdn.net/dardgen/article/details/18790977 虚函数 ,纯虚函数, 虚基类,它们都和virtual有关,这三个带有虚字的...

C++对象内存分析

一、问题的引出 对C++模型的认识可以从本质上提高对语言和各种机制的理解,如果对底层机制一无所知,那么很多高级的机制都只能通过死记硬背的方式来运用,而且有时候有错误,也很难找出原因。C++相对与C语...
  • ysu108
  • ysu108
  • 2012-05-24 17:00
  • 2691

C++虚基类的作用

虚基类的作用     当一个基类被声明为虚基类后,即使它成为了多继承链路上的公共基类,最后的派生类中也只有它的一个备份。例如:class CBase { };class CDerive1:virtua...

C++虚基类的作用、用法和意义

教科书上面对C++虚基类的描述玄而又玄,名曰“共享继承”,名曰“各派生类的对象共享基类的的一个拷贝”,其实说白了就是解决多重多级继承造成的二义性问题。例如有基类B,从B派生出C和D,然后类F又同时继承...

学习笔记32-设计模式

设计模式(Designs Patterns)设计模式,可以理解为一些面向对象代码设计的经验的总结。 使用设计模式,是为了可重用代码,使代码更容易被人理解,保证代码的可靠性。 JAVA常用的设计模式...

设计模式C++实现(4)——单例模式

软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。最...

详解大端模式和小端模式

详解大端模式和小端模式 一、大端模式和小端模式的起源         关于大端小端名词的由来,有一个有趣的故事,来自于Jonathan Swift的《格利佛游记》:Lilliput和Blefuscu这...
  • ce123
  • ce123
  • 2011-11-16 20:21
  • 107405

值得推荐的C/C++框架和库 (真的很强大)

值得学习的C语言开源项目 - 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具。它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作...

C++中虚析构函数的作用

我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明:        有下面的两个类:class ClxBase{public:  &#...

多继承与虚基类

  • 2013-05-14 19:01
  • 24KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)