首页 技术 正文
技术 2022年11月14日
0 收藏 718 点赞 4,161 浏览 2649 个字

C++多重继承下,对象布局与编译器,是否为虚拟继承都有很大关系,下面将逐一分析其中的差别,相同点为都按照类继承的先后顺序布局(类内按照虚表、成员声明先后顺序排列)。该类情况为子类按照继承顺序排列,如class C:public B,public A此种情况布局如下:

C++ 类继承的对象布局

如果class B,A带有虚函数,情况又发生了变化:

考虑下面的情况:

C++ 类继承的对象布局

class D {
int d;
public:
virtual void fun() {}
virtual ~D() {}
};class E {
public:
virtual void fun() {}
virtual ~E() {}
private:
int e;
};class F:public D,public E {
public:
void fun() {D.fun();}
virtual ~F() {}
private:
int f;
};

类F函数的布局中无虚表(vs2010,20个字节):

class Fsize(20):
+---
| +--- (base class D)
0| | {vfptr}
4| | d
| +---
| +--- (base class E)
8| | {vfptr}
12| | e
| +---
16| f
+---

g++ 编译器中包含虚表:

Class F    size=20 align=4   base size=20 base align=4    F (0x2ea1740) 0
vptr=((& F::_ZTV1F) + 8u)
D (0x2e76b28) 0
primary-for F (0x2ea1740)
E (0x2e76b60) 8
vptr=((& F::_ZTV1F) + 28u)

2)  当出现基类重复继承情况

如非虚拟继承,重复继承,编译器会产生告警信息:

warning: direct base ‘D’ inaccessible in ‘G’ due to ambiguity [enabled by default]

C++ 类继承的对象布局

编译器产生的布局与情况1)相同,都是按照继承的顺序排列

3) 虚拟继承(非菱形继承)

基类若非包含继承同一个父类,虚拟继承实际不存在,考虑下面的继承体系:

C++ 类继承的对象布局

类F继承自类D,类G虚拟继承D,F,类的布局图如下(与情况1相同):

g++ -fdump-class-hierarchy -c multiInherit.cpp
Class H
size=32 align=4
base size=4 base align=4
H (0x2372b80) 0 nearly-empty
vptridx=0u vptr=((& H::_ZTV1H) + 16u)
D (0x231b9d8) 4 virtual
vptridx=4u vbaseoffset=-12 vptr=((& H::_ZTV1H) + 40u)
F (0x2372bc0) 12 virtual
vptridx=8u vbaseoffset=-16 vptr=((& H::_ZTV1H) + 68u)
D (0x231ba10) 12
primary-for F (0x2372bc0) E (0x231ba48) 20 vptridx=12u vptr=((& H::_ZTV1H) + 88u)

vs2010 编译布局与cl -d1reportAllClassLayout multiInherit.cpp,与类G布局不同,类H这里产生了虚表:

class Hsize(32):
+---
0| {vbptr}
+---
+--- (virtual base D)
4| {vfptr}
8| d
+---
+--- (virtual base F)
| +--- (base class D)
12| | {vfptr}
16| | d
| +---
| +--- (base class E)
20| | {vfptr}
24| | e
| +---
28| f
+---

4) 虚拟继承(菱形继承)

菱形继承情况如下

C++ 类继承的对象布局

无论类K是否虚拟自I,J,g++产生的类布局都相似(基类都产生虚表,不过地址指向同一内存):

g++ -fdump-class-hierarchy -c multiInherit.cpp
Class K
size=16 align=4
base size=8 base align=4
K (0x237f340) 0
vptridx=0u vptr=((& K::_ZTV1K) + 12u)
I (0x237f380) 0 nearly-empty
primary-for K (0x237f340)
subvttidx=4u
D (0x231bc40) 8 virtual
vptridx=20u vbaseoffset=-12 vptr=((& K::_ZTV1K) + 56u)
J (0x237f3c0) 4 nearly-empty
subvttidx=12u vptridx=24u vptr=((& K::_ZTV1K) + 32u)
D (0x231bc40) alternative-path

类L的布局如下:

Class L
size=16 align=4
base size=4 base align=4
L (0x237f680) 0 nearly-empty
vptridx=0u vptr=((& L::_ZTV1L) + 24u)
I (0x237f6c0) 0 nearly-empty virtual
primary-for L (0x237f680)
subvttidx=16u vptridx=4u vbaseoffset=-20
D (0x231bd58) 4 virtual
vptridx=8u vbaseoffset=-12 vptr=((& L::_ZTV1L) + 48u)
J (0x237f700) 12 nearly-empty virtual
subvttidx=24u vptridx=12u vbaseoffset=-24 vptr=((& L::_ZTV1L) + 76u)
D (0x231bd58) alternative-path

VS 2010产生的类布局与是否虚拟继承有很大关系,未虚拟继承将不产生虚表且相同基类排列在子类下面而非其子类的父类下:

cl -d1reportAllClassLayout multiInherit.cpp
class Ksize(16):
+---
| +--- (base class I)
0| | {vbptr}
| +---
| +--- (base class J)
4| | {vbptr}
| +---
+---
+--- (virtual base D)
8| {vfptr}
12| d
+---

类L的布局产生了虚表,且重新排列了基类顺序:

class Lsize(20):
+---
0| {vbptr}
+---
+--- (virtual base D)
4| {vfptr}
8| d
+---
+--- (virtual base I)
12| {vbptr}
+---
+--- (virtual base J)
16| {vbptr}
+---
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,083
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,558
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,407
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,180
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,816
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,899