C++对象模型-4

前言


前两篇主要介绍了C++对象在一级继承体系下的对象模型,接下来将考虑二级继承体系下常用的菱形继承对象模型的影响和变化,主要包括普通菱形继承和虚拟菱形继承

菱形继承


普通菱形继承类


公共基类简单实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class B
{
public:
B(int var = 10): _b(var){};
~B() {}
public:
virtual void Run(void)
{
std::cout << "B Run()" << std::endl;
}
virtual void RunB(void)
{
std::cout << "B RunB()" << std::endl;
}
private:
int _b;
};

普通菱形继承类简单实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class D1 : public B
{
public:
D1(int var = 20): B(var),_d1(var) {};
~D1() {}
public:
virtual void Run(void)
{
std::cout << "D1 Run()" << std::endl;
}
virtual void RunD1(void)
{
std::cout << "D1 RunD1()" << std::endl;
}
private:
int _d1;
};

class D2 : public B
{
public:
D2(int var = 20) : B(var), _d2(var) {};
~D2() {}
public:
virtual void Run(void)
{
std::cout << "D2 Run()" << std::endl;
}
virtual void RunD2(void)
{
std::cout << "D2 RunD2()" << std::endl;
}
private:
int _d2;
};


class Rhombus : public D1, public D2
{
public:
Rhombus(int var = 30) : D1(var), D2(var), _rhombus(var) {};
~Rhombus() {}
public:
virtual void Run(void)
{
std::cout << "Rhombus Run()" << std::endl;
}
virtual void RunRhombus(void)
{
std::cout << "Rhombus RunRhombus()" << std::endl;
}
private:
int _rhombus;
};

Gcc命令的内存布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Vtable for Rhombus
Rhombus::_ZTV7Rhombus: 11 entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI7Rhombus)
16 (int (*)(...))Rhombus::Run
24 (int (*)(...))B::RunB
32 (int (*)(...))D1::RunD1
40 (int (*)(...))Rhombus::RunRhombus
48 (int (*)(...))-16
56 (int (*)(...))(& _ZTI7Rhombus)
64 (int (*)(...))Rhombus::_ZThn16_N7Rhombus3RunEv
72 (int (*)(...))B::RunB
80 (int (*)(...))D2::RunD2

Class Rhombus
size=40 align=8
base size=36 base align=8
Rhombus (0x0x7fb760cebaf0) 0
vptr=((& Rhombus::_ZTV7Rhombus) + 16)
D1 (0x0x7fb760844c98) 0
primary-for Rhombus (0x0x7fb760cebaf0)
B (0x0x7fb76088d2a0) 0
primary-for D1 (0x0x7fb760844c98)
D2 (0x0x7fb760844d00) 16
vptr=((& Rhombus::_ZTV7Rhombus) + 64)
B (0x0x7fb76088d300) 16
primary-for D2 (0x0x7fb760844d00)

可以看到普通菱形继承类的内存空间特点是基类Di的内存布局(按照继承的顺序依次布局基类)+子类的成员变量,基类Di的内存布局包括公共基类B的内存布局和基类Di的成员变量。子类的虚函数在继承而来的第一个继承的Di基类的虚函数表基础上进行替换(override),新增子类(新的虚函数),保持操作(没有override)。可以看到普通菱形继承内存中存在多份公共基类B的结构,这样存在二义性的问题,如对于Rhombus类调用Run方法,由于两个子类D1,D2都重写了,且都继承来了,不知道调用哪个子类的方法

内存布局的代码验证

1.测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
void RhombusCommonDeriveTest(void)
{
Rhombus d;
std::cout << "---------begin rhombus common derive object inner memory layout test-------" << std::endl;

std::cout << " object size is: " << sizeof(d) << std::endl;
std::cout << " object addr is: " << &d << std::endl; // d指针转换为long指针
std::cout << " typeid(d) is: " << typeid(d).name() << std::endl; // d对象类型
std::cout << "------ d1 obj begin -----" << std::endl;
std::cout << " object d1 vfptr addr is: " << (long*)*(long*)&d << std::endl; // d1 vfptr地址 在对象第1个位置
std::cout << " object d1 vfptr[0] func ptr is: " << (long*)*(long*)(*(long*)&d) << std::endl; //vfptr[0]的值
std::cout << " object d1 vfptr[0] func invoke res: ";
pFunc pRun = (pFunc)(*(long*)(*(long*)&d));
(*pRun)(); //调用vfptr[0](函数地址值)指向的函数

std::cout << " object d1 vfptr[1] func ptr is: " << (long*)*((long*)(*(long*)&d) + 1) << std::endl; //vfptr[1]的值
std::cout << " object d1 vfptr[1] func invoke res: ";
pFunc pRunB = (pFunc)(*((long*)(*(long*)&d) + 1));
(*pRunB)(); //调用vfptr[1](函数地址值)指向的函数
std::cout << " object d1 vfptr[2] func ptr is: " << (long*)*((long*)(*(long*)&d) + 2) << std::endl; //vfptr[2]的值
std::cout << " object d1 vfptr[2] func invoke res: ";
pFunc pRunD1 = (pFunc)(*((long*)(*(long*)&d) + 2));
(*pRunD1)(); //调用vfptr[2](函数地址值)指向的函数
std::cout << " object d1 vfptr[3] func ptr is: " << (long*)*((long*)(*(long*)&d) + 3) << std::endl; //vfptr[3]的值
std::cout << " object d1 vfptr[3] func invoke res: ";
pFunc pRunRhombus = (pFunc)(*((long*)(*(long*)&d) + 3));
(*pRunRhombus)(); //调用vfptr[3](函数地址值)指向的函数

std::cout << " object _b addr is: " << (long*)&d + 1 << std::endl; //_b 在对象第2个位置
std::cout << " object _b value is: " << (int)*((long*)&d + 1) << std::endl;

std::cout << " object _d1 addr is: " << (long*)((int*)((long*)&d + 1) + 1) << std::endl; //_d1 在对象第3个位置
std::cout << " object _d1 value is: " << *((int*)((long*)&d + 1) + 1)<< std::endl;
std::cout << "------ d1 obj end -----" << std::endl;

std::cout << "------ d2 obj begin -----" << std::endl;
std::cout << " object d2 vfptr addr is: " << (long*)*((long*)&d + 2) << std::endl; // d2 vfptr地址 在对象第4个位置
std::cout << " object d2 vfptr[0] func ptr is: " << (long*)*(long*)(*((long*)&d + 2)) << std::endl; //vfptr[0]的值
std::cout << " object d2 vfptr[0] func invoke res: ";
pFunc pRun2 = (pFunc)(*(long*)(*((long*)&d + 2)));
(*pRun2)(); //调用vfptr[0](函数地址值)指向的函数
std::cout << " object d2 vfptr[1] func ptr is: " << (long*)*((long*)(*((long*)&d + 2)) + 1) << std::endl; //vfptr[1]的值
std::cout << " object d2 vfptr[1] func invoke res: ";
pFunc pRunB2 = (pFunc)(*((long*)(*((long*)&d + 2)) + 1));
(*pRunB2)(); //调用vfptr[1](函数地址值)指向的函数
std::cout << " object d2 vfptr[2] func ptr is: " << (long*)*((long*)(*((long*)&d + 2)) + 2) << std::endl; //vfptr[2]的值
std::cout << " object d2 vfptr[2] func invoke res: ";
pFunc pRunD2 = (pFunc)(*((long*)(*((long*)&d + 2)) + 2));
(*pRunD2)(); //调用vfptr[2](函数地址值)指向的函数

std::cout << " object _b addr is: " << (long*)&d + 3 << std::endl; //_b 在对象第5个位置
std::cout << " object _b value is: " << (int)*((long*)&d + 3) << std::endl;

std::cout << " object _d2 addr is: " << (long*)((int*)((long*)&d + 3) + 1) << std::endl; //_base2_var 在对象第6个位置
std::cout << " object _d2 value is: " << *((int*)((long*)&d + 3) + 1)<< std::endl;
std::cout << "------ d2 obj end -----" << std::endl;

std::cout << " object _rhombus addr is: " << (long*)&d + 4 << std::endl; //_rhombus 在对象第7个位置
std::cout << " object _rhombus value is: " << (int)*((long*)&d + 4) << std::endl;

std::cout << "---------end rhombus common derive object inner memory layout test-------" << std::endl;

}

2.运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
---------begin rhombus common derive object inner memory layout test-------
object size is: 40
object addr is: 0x7fff8b599920
typeid(d) is: 7Rhombus
------ d1 obj begin -----
object d1 vfptr addr is: 0x563b8f869a88
object d1 vfptr[0] func ptr is: 0x563b8f86489c
object d1 vfptr[0] func invoke res: Rhombus Run()
object d1 vfptr[1] func ptr is: 0x563b8f8645e4
object d1 vfptr[1] func invoke res: B RunB()
object d1 vfptr[2] func ptr is: 0x563b8f8646ca
object d1 vfptr[2] func invoke res: D1 RunD1()
object d1 vfptr[3] func ptr is: 0x563b8f8648e2
object d1 vfptr[3] func invoke res: Rhombus RunRhombus()
object _b addr is: 0x7fff8b599928
object _b value is: 30
object _d1 addr is: 0x7fff8b59992c
object _d1 value is: 30
------ d1 obj end -----
------ d2 obj begin -----
object d2 vfptr addr is: 0x563b8f869ab8
object d2 vfptr[0] func ptr is: 0x563b8f8648d7
object d2 vfptr[0] func invoke res: Rhombus Run()
object d2 vfptr[1] func ptr is: 0x563b8f8645e4
object d2 vfptr[1] func invoke res: B RunB()
object d2 vfptr[2] func ptr is: 0x563b8f8647b0
object d2 vfptr[2] func invoke res: D2 RunD2()
object _b addr is: 0x7fff8b599938
object _b value is: 30
object _d2 addr is: 0x7fff8b59993c
object _d2 value is: 30
------ d2 obj end -----
object _rhombus addr is: 0x7fff8b599940
object _rhombus value is: 30
---------end rhombus common derive object inner memory layout test-------

3.内存布局示意图:
rhombus common derive

虚拟菱形继承类


简单实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class D1_Virtual : virtual public B
{
public:
D1_Virtual(int var = 20) : B(var), _d1_virtual(var) {};
~D1_Virtual() {}
public:
virtual void Run(void)
{
std::cout << "D1_Virtual Run()" << std::endl;
}
virtual void RunD1_Virtual(void)
{
std::cout << "D1_Virtual RunD1_Virtual()" << std::endl;
}
private:
int _d1_virtual;
};

class D2_Virtual : virtual public B
{
public:
D2_Virtual(int var = 20) : B(var), _d2_virtual(var) {};
~D2_Virtual() {}
public:
virtual void Run(void)
{
std::cout << "D2_Virtual Run()" << std::endl;
}
virtual void RunD2_Virtual(void)
{
std::cout << "D2_Virtual RunD2_Virtual()" << std::endl;
}
private:
int _d2_virtual;
};

class Rhombus_Virtual : public D1_Virtual, public D2_Virtual
{
public:
Rhombus_Virtual(int var = 30) : D1_Virtual(var), D2_Virtual(var), _rhombus_virtual(var) {};
~Rhombus_Virtual() {}
public:
virtual void Run(void)
{
std::cout << "Rhombus_Virtual Run()" << std::endl;
}
virtual void RunRhombus_Virtual(void)
{
std::cout << "Rhombus_Virtual RunRhombus_Virtual()" << std::endl;
}
private:
int _rhombus_virtual;
};

Gcc命令的内存布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Vtable for Rhombus_Virtual
Rhombus_Virtual::_ZTV15Rhombus_Virtual: 17 entries
0 32
8 (int (*)(...))0
16 (int (*)(...))(& _ZTI15Rhombus_Virtual)
24 (int (*)(...))Rhombus_Virtual::Run
32 (int (*)(...))D1_Virtual::RunD1_Virtual
40 (int (*)(...))Rhombus_Virtual::RunRhombus_Virtual
48 16
56 (int (*)(...))-16
64 (int (*)(...))(& _ZTI15Rhombus_Virtual)
72 (int (*)(...))Rhombus_Virtual::_ZThn16_N15Rhombus_Virtual3RunEv
80 (int (*)(...))D2_Virtual::RunD2_Virtual
88 0
96 18446744073709551584
104 (int (*)(...))-32
112 (int (*)(...))(& _ZTI15Rhombus_Virtual)
120 (int (*)(...))Rhombus_Virtual::_ZTv0_n24_N15Rhombus_Virtual3RunEv
128 (int (*)(...))B::RunB

Construction vtable for D1_Virtual (0x0x7fb7608afdd0 instance) in Rhombus_Virtual
Rhombus_Virtual::_ZTC15Rhombus_Virtual0_10D1_Virtual: 11 entries
0 32
8 (int (*)(...))0
16 (int (*)(...))(& _ZTI10D1_Virtual)
24 (int (*)(...))D1_Virtual::Run
32 (int (*)(...))D1_Virtual::RunD1_Virtual
40 0
48 18446744073709551584
56 (int (*)(...))-32
64 (int (*)(...))(& _ZTI10D1_Virtual)
72 (int (*)(...))D1_Virtual::_ZTv0_n24_N10D1_Virtual3RunEv
80 (int (*)(...))B::RunB

Construction vtable for D2_Virtual (0x0x7fb7608aff70 instance) in Rhombus_Virtual
Rhombus_Virtual::_ZTC15Rhombus_Virtual16_10D2_Virtual: 11 entries
0 16
8 (int (*)(...))0
16 (int (*)(...))(& _ZTI10D2_Virtual)
24 (int (*)(...))D2_Virtual::Run
32 (int (*)(...))D2_Virtual::RunD2_Virtual
40 0
48 18446744073709551600
56 (int (*)(...))-16
64 (int (*)(...))(& _ZTI10D2_Virtual)
72 (int (*)(...))D2_Virtual::_ZTv0_n24_N10D2_Virtual3RunEv
80 (int (*)(...))B::RunB

VTT for Rhombus_Virtual
Rhombus_Virtual::_ZTT15Rhombus_Virtual: 7 entries
0 ((& Rhombus_Virtual::_ZTV15Rhombus_Virtual) + 24)
8 ((& Rhombus_Virtual::_ZTC15Rhombus_Virtual0_10D1_Virtual) + 24)
16 ((& Rhombus_Virtual::_ZTC15Rhombus_Virtual0_10D1_Virtual) + 72)
24 ((& Rhombus_Virtual::_ZTC15Rhombus_Virtual16_10D2_Virtual) + 24)
32 ((& Rhombus_Virtual::_ZTC15Rhombus_Virtual16_10D2_Virtual) + 72)
40 ((& Rhombus_Virtual::_ZTV15Rhombus_Virtual) + 120)
48 ((& Rhombus_Virtual::_ZTV15Rhombus_Virtual) + 72)

Class Rhombus_Virtual
size=48 align=8
base size=32 base align=8
Rhombus_Virtual (0x0x7fb760cebb60) 0
vptridx=0 vptr=((& Rhombus_Virtual::_ZTV15Rhombus_Virtual) + 24)
D1_Virtual (0x0x7fb7608afdd0) 0
primary-for Rhombus_Virtual (0x0x7fb760cebb60)
subvttidx=8
B (0x0x7fb7609461e0) 32 virtual
vptridx=40 vbaseoffset=-24 vptr=((& Rhombus_Virtual::_ZTV15Rhombus_Virtual) + 120)
D2_Virtual (0x0x7fb7608aff70) 16
subvttidx=24 vptridx=48 vptr=((& Rhombus_Virtual::_ZTV15Rhombus_Virtual) + 72)
B (0x0x7fb7609461e0) alternative-path

可以看到虚拟菱形继承类的内存空间特点是基类Di的内存布局(按照继承的顺序依次布局基类)+子类的成员变量+共同虚基类B的内存布局,基类Di的内存布局包括基类Di的虚函数表和虚基表和基类Di的成员变量。子类的虚函数在继承而来的第一个继承的Di基类的虚函数表基础上进行新增子类操作(新的虚函数)。可以看到虚拟菱形继承内存中只存在一份公共基类B的结构,这样可以解决二义性问题

内存布局的代码验证

1.测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
void RhombusVirtualDeriveTest(void)
{
Rhombus_Virtual d;
std::cout << "---------begin rhombus virtual derive object inner memory layout test-------" << std::endl;

std::cout << " object size is: " << sizeof(d) << std::endl;
std::cout << " object addr is: " << &d << std::endl; // d指针转换为long指针
std::cout << " typeid(d) is: " << typeid(d).name() << std::endl; // d对象类型

std::cout << "------ d1 obj begin -----" << std::endl;
std::cout << " object d1 vfptr addr is: " << (long*)&d << std::endl; // d1 vfptr地址 在对象第1个位置
std::cout << " object d1 vfptr value is: " << (long*)*(long*)&d << std::endl;
std::cout << " object d1 vfptr[0] func ptr is: " << (long*)*(long*)(*(long*)&d) << std::endl; //vfptr[0]的值
std::cout << " object d1 vfptr[0] func invoke res: ";
pFunc pRun = (pFunc)(*(long*)(*(long*)&d));
(*pRun)(); //调用vfptr[0](函数地址值)指向的函数
std::cout << " object d1 vfptr[1] func ptr is: " << (long*)*((long*)(*(long*)&d) + 1) << std::endl; //vfptr[1]的值
std::cout << " object d1 vfptr[1] func invoke res: ";
pFunc pRunD1 = (pFunc)(*((long*)(*(long*)&d) + 1));
(*pRunD1)(); //调用vfptr[1](函数地址值)指向的函数
std::cout << " object d1 vfptr[2] func ptr is: " << (long*)*((long*)(*(long*)&d) + 2) << std::endl; //vfptr[2]的值
std::cout << " object d1 vfptr[2] func invoke res: ";
pFunc pRunRhombus = (pFunc)(*((long*)(*(long*)&d) + 2));
(*pRunRhombus)(); //调用vfptr[2](函数地址值)指向的函数
std::cout << " object d1 vptr offset is: " << (int)*((long*)(*(long*)&d) + 3) << std::endl; //vfptr[3]的值
std::cout << " object d1 vbase offset is: " << (int)*((long*)(*(long*)&d) + 4) << std::endl; //vfptr[4]的值
std::cout << " object _d1_virtual addr is: " << (long*)&d + 1 << std::endl; // _d1_virtual 地址 在对象第2个位置
std::cout << " object _d1_virtual value is: " << (int)*((long*)&d + 1) << std::endl;
std::cout << "------ d1 obj end -----" << std::endl;

std::cout << "------ d2 obj begin -----" << std::endl;
std::cout << " object d2 vfptr addr is: " << (long*)&d + 2 << std::endl; // d2 vfptr地址 在对象第3个位置
std::cout << " object d2 vfptr value is: " << (long*)*((long*)&d + 2) << std::endl;
std::cout << " object d2 vfptr[0] func ptr is: " << (long*)*(long*)(*((long*)&d + 2)) << std::endl; //vfptr[0]的值
std::cout << " object d2 vfptr[0] func invoke res: ";
pFunc pRun2 = (pFunc)(*(long*)(*((long*)&d + 2)));
(*pRun2)(); //调用vfptr[0](函数地址值)指向的函数
std::cout << " object d2 vfptr[1] func ptr is: " << (long*)*((long*)(*((long*)&d + 2)) + 1) << std::endl; //vfptr[1]的值
std::cout << " object d2 vfptr[1] func invoke res: ";
pFunc pRunD2 = (pFunc)(*((long*)(*((long*)&d + 2)) + 1));
(*pRunD2)(); //调用vfptr[1](函数地址值)指向的函数
std::cout << " object d2 vptr offset is: " << (int)*((long*)(*((long*)&d + 2)) + 2) << std::endl; //vfptr[2]的值
std::cout << " object d2 vbase offset is: " << (int)*((long*)(*((long*)&d + 2)) + 3) << std::endl; //vfptr[3]的值
std::cout << " object _d2_virtual addr is: " << (long*)&d + 3 << std::endl; //_d2 在对象第4个位置
std::cout << " object _d2_virtual value is: " << (int)*((long*)&d + 3) << std::endl;
std::cout << " object _rhombus_virtual addr is: " << (long*)((int*)((long*)&d + 3) + 1) << std::endl; // _rhombus_virtual 地址 在对象第5个位置
std::cout << " object _rhombus_virtual value is: " << *((int*)((long*)&d + 3) + 1) << std::endl;
std::cout << "------ d2 obj end -----" << std::endl;

std::cout << "------ base obj begin -----" << std::endl;
std::cout << " object base vfptr addr is: " << (long*)&d + 4 << std::endl; // base vfptr地址 在对象第6个位置
std::cout << " object base vfptr value is: " << (long*)*((long*)&d + 4) << std::endl;
std::cout << " object base vfptr[0] func ptr is: " << (long*)*(long*)(*((long*)&d + 4)) << std::endl; //vfptr[0]的值
// std::cout << " object base vfptr[0] func invoke res: ";
// pFunc pRunGen = (pFunc)(*(long*)(*((long*)&d + 4)));
// (*pRunGen)(); //调用vfptr[0](函数地址值)指向的函数
std::cout << " object base vfptr[1] func ptr is: " << (long*)*((long*)(*((long*)&d + 4)) + 1) << std::endl; //vfptr[0]的值
std::cout << " object base vfptr[1] func invoke res: ";
pFunc pRunB = (pFunc)(*((long*)(*((long*)&d + 4)) + 1));
(*pRunB)(); //调用vfptr[1](函数地址值)指向的函数

std::cout << " object _b addr is: " << (long*)&d + 5 << std::endl; //_b 在对象第7个位置
std::cout << " object _b value is: " << (int)*((long*)&d + 5) << std::endl;
std::cout << "------ base obj end -----" << std::endl;


std::cout << "---------end rhombus virtual derive object inner memory layout test-------" << std::endl;

}

2.运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---------begin rhombus virtual derive object inner memory layout test-------
object size is: 48
object addr is: 0x7fff5a2ecef0
typeid(d) is: 15Rhombus_Virtual
------ d1 obj begin -----
object d1 vfptr addr is: 0x7fff5a2ecef0
object d1 vfptr value is: 0x55573fd45920
object d1 vfptr[0] func ptr is: 0x55573fd40c6e
object d1 vfptr[0] func invoke res: Rhombus_Virtual Run()
object d1 vfptr[1] func ptr is: 0x55573fd409fc
object d1 vfptr[1] func invoke res: D1_Virtual RunD1_Virtual()
object d1 vfptr[2] func ptr is: 0x55573fd40cc0
object d1 vfptr[2] func invoke res: Rhombus_Virtual RunRhombus_Virtual()
object d1 vptr offset is: 16
object d1 vbase offset is: -16
object _d1_virtual addr is: 0x7fff5a2ecef8
object _d1_virtual value is: 30
------ d1 obj end -----
------ d2 obj begin -----
object d2 vfptr addr is: 0x7fff5a2ecf00
object d2 vfptr value is: 0x55573fd45950
object d2 vfptr[0] func ptr is: 0x55573fd40cb6
object d2 vfptr[0] func invoke res: Rhombus_Virtual Run()
object d2 vfptr[1] func ptr is: 0x55573fd40b16
object d2 vfptr[1] func invoke res: D2_Virtual RunD2_Virtual()
object d2 vptr offset is: 0
object d2 vbase offset is: -32
object _d2_virtual addr is: 0x7fff5a2ecf08
object _d2_virtual value is: 30
object _rhombus_virtual addr is: 0x7fff5a2ecf0c
object _rhombus_virtual value is: 30
------ d2 obj end -----
------ base obj begin -----
object base vfptr addr is: 0x7fff5a2ecf10
object base vfptr value is: 0x55573fd45980
object base vfptr[0] func ptr is: 0x55573fd40ca9
object base vfptr[1] func ptr is: 0x55573fd405e4
object base vfptr[1] func invoke res: B RunB()
object _b addr is: 0x7fff5a2ecf18
object _b value is: 10
------ base obj end -----
---------end rhombus virtual derive object inner memory layout test-------

3.内存布局示意图:
rhombus virtual derive

总结


本篇主要介绍了C++类在菱形继承体系下类对象内存特点。可以看出,对于普通菱形继承继承,最终的子类对象中会存在共同基类的多份拷贝,当子类调用共同基类中的相同函数时会存在二义性问题,为了解决这个问题,最好是在第二层继承体系中使用虚拟继承,这样在最终的子类的内存中会仅有一个共同基类的拷贝,主要是因为最终子类的多个虚基表都指向同一个虚基类,对于虚函数表依然遵守前几篇介绍的基本原则,由于菱形继承肯定是多重继承,所以最终子类有多张虚函数表,对于虚拟情况下的菱形继承还存在多张虚基表