虚拟继承与菱形虚拟继承

来源:互联网 发布:大数据建设 一流公司 编辑:程序博客网 时间:2024/05/07 03:29

虚拟继承

什么是虚拟继承?
虚拟继承是C++编程语言中的一种语法,使得派生类如果继承基类多次,只有一份基类的拷贝在派生类对象中。需在在继承方式前加上virtual。

#include<iostream>using namespace std;class B{public:    int _b;};class D:virtual public B{public:    int _d;};int main(){    D d;    d._b = 1;    d._d = 2;    return 0;}

这是一个简单的单虚拟继承。相关赋值后我们去内存看看派生类对象的模型。

这里写图片描述
我们看到第二行存放的是_d的值,最后一行存放的是_b的值。那么第一行这一串数据是什么呢?这其实是一个地址(偏移量表的地址),我们去这个地址看看里面存放了些什么。
这里写图片描述
这其中第一行的0代表着偏移量表相对于自己的偏移量,为0。第二行的8代表着偏移量表相对于基类的偏移量,为8。

单虚拟继承派生类的空间模型

这里写图片描述

我们去看看反汇编代码

这里写图片描述

我们发现在调用D构造函数之前有push 1这样的代码,这其实是虚拟继承的标志。

派生类D的构造函数到底做了什么,要访问基类成员应该怎么访问?
偏移量表的地址由派生类D的构造函数填写,要想访问基类成员,首先要去找偏移量表,之后根据与基类的偏移量进行访问。

菱形虚拟继承

回想菱形继承,一个派生类D继承了基类C1,C2。C1与C2同时继承了相同的基类B。当我们直接由派生类对象d对基类B的成员进行操作时,会出现二义性的问题。因为编译器不知道你所说的基类B是C1所继承的还是C2所继承的。
虚拟继承完美的解决了这个问题。 派生类D如果继承了多次基类,只有一份基类的拷贝在派生类内。

问题来了,虚拟继承应该发生在那个地方?
这个问题很简单,如果发生在派生类D多继承C1,C2时,C1,C2已经同时继承了基类B,届时派生类D中已经存在了两份基类B的拷贝。因此虚拟继承应该发生在C1,C2继承基类B时。
这里写图片描述

#include<iostream>using namespace std;class B{public:    int _b;};class C1:virtual public B{public:    int _c1;};class C2:virtual public B{public:    int _c2;};class D:public C1,public C2{public:    int _d;};int main(){    D d;    d._b = 1;    d._c1 = 2;    d._c2 = 3;    d._d = 4;    return 0;}

同样我们看看派生类d在内存中的模型。
这里写图片描述
首先我们看到第二行存放_c1的值,第四行存放_c2的值,接着就是_d,在最底部存放_b。同样这其中存放了两个偏移量表的地址。我们去分别看看两张偏移量表有什么不同。
先去0x0129580c看看
这里写图片描述
同样第一行是偏移量表相对自己的偏移量为0。第二行是偏移量表相对基类B的偏移量为14(十六进制,十进制为20)。

之后去0x01295800看看
0x01295800
第一行是偏移量表相对自己的偏移量为0。第二行是偏移量表相对基类B的偏移量为0c(十六进制,十进制为12)。

我们可以得出派生类对象d的模型
这里写图片描述
我们可以看到派生类对象内部只存放了一份基类拷贝,这时对基类成员_b进行赋值时不会出现二义性问题。

原创粉丝点击