1. 菱形继承
1)概念
? B,C继承自A,D继承自B,C
2)问题
? 一个派生类中保留间接基类的多份同名成员,可能出现命名冲突和冗余数据问题
2. 虚继承
c++代码示例:
#include <stdio.h>
//定义家具类,虚基类,等同于类A
class Furniture {
public:
Furniture() {
printf("Furniture::Furniture()\n");
price = 0;
}
virtual ~Furniture(){ //家具类的虚析构函数
printf("Furniture::~Furniture()\n");
}
virtual int getPrice() { //获取家具价格
printf("Furniture::getPrice()\n");
return price;
};
protected:
int price; //家具类的成员变量
};
//定义沙发类,继承自类Furniture,等同于类B
class Sofa : virtual public Furniture {
public:
Sofa() {
printf("Sofa::Sofa()\n");
price = 1;
color = 2;
}
virtual ~Sofa() { //沙发类虚析构函数
printf("Sofa::~Sofa()\n");
}
virtual int getColor() { //获取沙发颜色
printf("Sofa::getColor()\n");
return color;
}
virtual int sitDown() { //沙发可以坐下休息
return printf("Sofa::sitDown()\n");
}
protected:
int color; // 沙发类成员变量
};
//定义床类,继承自类Furniture,等同于类C
class Bed : virtual public Furniture {
public:
Bed() {
printf("Bed::Bed()\n");
price = 3;
length = 4;
width = 5;
}
virtual ~Bed(){ //床类的虚析构函数
printf("Bed::~Bed()\n");
}
virtual int getArea(){ //获取床面积
printf("Bed::getArea()\n");
return length * width;
}
virtual int sleep(){ //床可以用来睡觉
return printf("Bed::sleep()\n");
}
protected:
int length; //床类成员变量
int width;
};
//子类沙发床的定义,派生自类Sofa和类Bed,等同于类D
class SofaBed : public Sofa, public Bed {
public:
SofaBed() {
printf("SofaBed::SofaBed()\n");
height = 6;
}
virtual ~SofaBed(){ //沙发床类的虚析构函数
printf("SofaBed::~SofaBed()\n");
}
virtual int sitDown(){ //沙发可以坐下休息
return printf("SofaBed::sitDown()\n");
}
virtual int sleep(){ //床可以用来睡觉
return printf("SofaBed::sleep()\n");
}
virtual int getHeight() {
printf("SofaBed::getHeight()\n");
return height;
}
protected:
int height; //沙发类的成员变量
};
int main(int argc, char* argv[]) {
SofaBed sofabed;
Furniture *p1 = &sofabed; //转换成虚基类指针
Sofa *p2 = &sofabed; //转换成父类指针
Bed *p3 = &sofabed; //转换成父类指针
printf("%p %p %p\n", p1, p2, p3);
return 0;
}
vs_x86汇编标识:
00401000 push ebp
00401001 mov ebp, esp
00401003 sub esp, 40h
00401006 push 1 ;是否构造虚基类的标志:1构造,0不构造 ①
00401008 lea ecx, [ebp-40h] ;传入对象的首地址作为this指针
0040100B call sub_4011D0 ;调用构造函数 ②
00401010 lea eax, [ebp-40h] ;获取对象的首地址
00401013 test eax, eax
00401015 jnz short loc_401020 ;检查代码
00401017 mov dword ptr [ebp-4], 0
0040101E jmp short loc_40102D
00401020 mov ecx, [ebp-3Ch] ;取出对象中的Sofa类虚基类偏移表第二项数据
;即虚基类对象首地址相对于虚基类偏移表的偏移值
00401023 mov edx, [ecx+4] ;取出偏移值并存入edx
00401026 lea eax, [ebp+edx-3Ch] ;根据虚基类偏移表,得到虚基类数据的所在地址 ③
0040102A mov [ebp-4], eax ;利用中间变量保存虚基类的首地址
0040102D mov ecx, [ebp-4]
00401030 mov [ebp-14h], ecx ;p1=&sofabed
00401033 lea edx, [ebp-40h] ;直接转换SofaBed对象的首地址为父类Sofa的指针 ④
00401036 mov [ebp-10h], edx ;p2=&sofabed
00401039 lea eax, [ebp-40h] ;获取对象SofaBed的首地址 ⑤
0040103C test eax, eax
0040103E jz short loc_40104B ;地址检查
00401040 lea ecx, [ebp-40h]
00401043 add ecx, 0Ch ;获取Bed类对象的首地址
00401046 mov [ebp-8], ecx ;利用中间变量保存Bed类对象的首地址
00401049 jmp short loc_401052
0040104B mov dword ptr [ebp-8], 0
00401052 mov edx, [ebp-8]
00401055 mov [ebp-0Ch], edx ;p3=&sofabed
00401058 mov eax, [ebp-0Ch]
0040105B push eax ;参数4:p3
0040105C mov ecx, [ebp-10h]
0040105F push ecx ;参数3:p2
00