(1)首先我们考虑一个(非虚拟)多重继承的相对简单的例子。看看下面的C++类层次结构:
注意Top被继承了两次(在Eiffel语言中这被称作重复继承)。
这意味着类型Bottom的一个实例bottom将有两个叫做a的元素(分别为bottom.Left::a和bottom.Right::a)
那么Buttom 在内存中是如何存储的呢:编译器建议如下(当然也可以Right放在Left上面呢 如图):
下面开始测试:
首先:
接着测:如果我们提升Bottom指针,会发生什么事呢?
如果 再
原因就在于:(肯定是暗箱操作的 暂时不想追究了 下面“参考”) 如图 (注意访问域 一定是继承之间共有的可以访问)
是的,什么也没有。这条语句是有歧义的:编译器将会报错。
是的,什么也没有。这条语句是有歧义的:编译器将会报错。
(二)多继承(虚拟继承)
//首先:@https://www.cnblogs.com/jin521/p/5602190.html //http://blog.csdn.net/stay_the_course/article/details/55259801
参考:1:http://blog.csdn.net/stay_the_course/article/details/55259801
2:https://www.cnblogs.com/malecrab/p/5572730.html
3:https://www.cnblogs.com/jin521/p/5602190.html
4:http://blog.csdn.net/cmm0401/article/details/66472391
5:插入什么是多态:https://www.cnblogs.com/liujinhong/p/6003144.html
6:https://www.cnblogs.com/Daywei/p/5865342.html
7:汇编:https://www.cnblogs.com/lxgeek/archive/2011/01/01/1923738.html
虚继承和虚函数是完全无相关的两个概念。
虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝。这将存在两个问题:其一,浪费存储空间;第二,存在二义性问题,通常可以将派生类对象的地址赋值给基类对象,实现的具体方式是,将基类指针指向继承类(继承类有基类的拷贝)中的基类对象的地址,但是多重继承可能存在一个基类的多份拷贝,这就出现了二义性。
虚继承可以解决多种继承前面提到的两个问题:
虚继承底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)(需要强调的是,虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了);当虚继承的子类被当做父类继承时,虚基类指针也会被继承。
实际上,vbptr指的是虚基类表指针(virtual base table pointer),该指针指向了一个虚基类表(virtual table),虚表中记录了虚基类与本类的偏移地址;通过偏移地址,这样就找到了虚基类成员,而虚继承也不用像普通多继承那样维持着公共基类(虚基类)的两份同样的拷贝,节省了存储空间
虚基类表存储的是虚基类相对直接继承类的偏移;而虚函数表存储的是虚函数地址。
理解虚继承:虚继承不同于真正的继承,多个派生类虚继承同一个基类,如图
菱形继承时:
转:c++ 对象模型:https://www.cnblogs.com/raichen/p/5744300.html
内存布局(看编译器)如下图:
访问被重复继承的基类时:如上图