菱形继承问题
先来看程序......
#include <iostream>
using namespace std;
class Animal{ //动物
public:
int m_Age;
};
class horse : public Animal{ // 马
};
class donkey : public Animal{ // 驴
};
class mule : public horse, public donkey{ // 骡子
};
void test()
{
mule m;
m.m_Age = 10; // 这里提示 "mule::m_Age"不明确
}
int main()
{
return 0;
}
上面程序的问题或许可以用作用域来区分一下,
#include <iostream>
using namespace std;
class Animal{ //动物
public:
int m_Age;
};
class horse : public Animal{ // 马
};
class donkey : public Animal{ // 驴
};
class mule : public horse, public donkey{ // 骡子
};
void test()
{
mule m;
m.horse::m_Age = 10;
m.donkey::m_Age = 12;
cout << "m.horse::m_Age: " << m.horse::m_Age << endl;
cout << "m.donkey::m_Age: " << m.donkey::m_Age << endl;
}
int main()
{
test();
return 0;
}
打印结果是
可以看到程序可以正常运行了,但是还有一个问题,就是骡子的年龄有了两个值(菱形继承导致存在两个数据),下来看一下底层
复制当前项目路径,然后打开 开发人员命令提示符(在开始菜单栏里) 输入命令:cl /d1 reportSingleClassLayoutmule "main.cpp" 报告单个类布局
从上图可以明显看到mule骡子类,继承到了连个数据,但一个骡子只能有一个年龄,因此利用虚继承解决菱形继承问题
#include <iostream>
using namespace std;
class Animal{ //动物 虚基类
public:
int m_Age;
};
class horse : virtual public Animal{ // 马
};
class donkey : virtual public Animal{ // 驴
};
class mule : public horse, public donkey{ // 骡子
};
void test()
{
mule m;
m.horse::m_Age = 10;
m.donkey::m_Age = 12;
//此时就可以写成 m.m_Age = 15; 也不会有问题了
cout << "m.horse::m_Age: " << m.horse::m_Age << endl;
cout << "m.donkey::m_Age: " << m.donkey::m_Age << endl;
}
int main()
{
test();
return 0;
}
此时程序结果就是 12 了,对m.horse::m_Age 、m.donkey::m_Age 操作的就是一块内存了,再来看看mule类的底层实现
vbptr 虚基类指针,horse类的虚基类指针指向 $vbtable@horse@,其中存储了一个偏移量 8,那么 0+8 就找到了 虚基类的m_Age的地址。donkey类的也是一样。