问题引入:
如果有Base类,B1类,B2类,D类,如下图继承关系
那么按一般的继承来看,D类创造的对象会继承B1类的方法与成员,同时也会继承B2类的方法与成员;
接下来类B1 , B2 会分别去继承Base类的方法与成员,那么D类的对象在调用Base类的方法时,到底是继承B1类这边的Base,还是会继承B2类这边的Base,此时就会产生二义性
为了解决这个问题,就看看虚拟继承是怎么来解决这个二义性问题的
菱形的虚拟继承的源代码
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base() " << this << endl;
}
~Base()
{
cout << "~Base() " << this << endl;
}
int m_data1;
};
class B1 : virtual public Base
{
public:
B1()
{
cout << "B1() " << this << endl;
}
~B1()
{
cout << "~B1() " << this << endl;
}
int m_data2;
};
class B2 : virtual public Base
{
public:
B2()
{
cout << "B2() " << this << endl;
}
~B2()
{
cout << "~B2() " << this << endl;
}
int m_data3;
};
class D : public B1, public B2
{
public:
D()
{
B1::m_data2 = 0x1;
B1::m_data1 = 0x2;
B2::m_data3 = 0x3;
B2::m_data1 = 0x4;
m_data4 = 0x5;
cout << "D()" << this << endl;
}
~D()
{
cout << "~D() " << this << endl;
}
int m_data4;
};
void Test()
{
D d;
//cout << sizeof(D) << endl; //24
}
int main()
{
Test();
getchar();
return 0;
}
2.断点打到D类的构造函数这条语句B1::m_data2 = 0x1;运行完D类构造函数后调试。
内存1中的地址栏输入&d可以看到类D对象的模型(取&d因为在Test()函数创建的是D类的d对象)
3.接下来问题就来了,明明是取D类对象d的地址,为什么这个地址下有存储了地址,里面到底是什么东 西,那就看看吧,(可以看看反汇编和相应的内存)
此处可以看到它的地址偏移4个字节中存储了0X 00 00 00 14
(这个数据有什么意义哪?)
在看看反汇编就可以了解到编译器到底在搞什么鬼
看看在给m_data1赋值时,也就是给类Base数据赋值时,是什么情况
―――――――――――――――――――――――――――――――――
第一步 取得this指针给寄存器eax
第二步 将寄存器eax中内容(即地址 (0x 00 B7 DC C8))给 ecx
第三步 将寄存器exc中内容加4 (即 地址(0x 00 B7 DC CC))后,取其地址内容给edx(内容为 0X 00 00 00 14)
第四步 取this指针给寄存器eax
第五步 eax + edx 的结果为 (0x 00 30 FD 60 + 0X 00 00 00 14 = 0x 00 30 FD 74),接下来将数据2
存放到这个地址下
――――――――――――――――――――――――――――――――――――――
从模型图可以看到地址(0x 00 30 FD 74)就是Base类的地址
为什么存放的是数据2,但是结果是4,这就要看清楚了,下面还有条语句未执行,
那就是 B2::m_data1 = 0x4;
这就是菱形虚拟继承下为了不产生二义性的奥妙
(D类继承Base类的方法与成员,编译器在内存中只开辟了一块)