//状态一情况下 类D大小是32, 代码如下:
class B{
public:
char b;
virtual void b(){}
};
class C{
public:
char c1;
char c2;
virtual void c1(){}
virtual void c2(){}
};
class D : public B, public C{
public:
int d;
virtual void b(){}
virtual void c1(){}
};
//sizeof(D) == 32;
//状态二情况下 类D大小是24, 代码如下:
class B{
public:
virtual void b(){}
};
class C{
public:
virtual void c1(){}
virtual void c2(){}
};
class D : public B, public C
{
public:
char b;
char c1;
char c2;
int d;
virtual void b(){}
virtual void c1(){}
};
//sizeof(D) == 24;
我的疑问 :
情景2的大小24是我预期的.但我预期情景1也应该是24,结果被打脸,程序输出是32.想不明白为什么是32.
变量在基类定义和变量都在派生类定义两种情况下,为什么会影响派生类的最终大小?
我想我搞明白了. 大家指正一下我下面理解的对不对:
在情景1计算类D大小的步骤:
(1)计算虚表指针: 类D中一共有两个虚表指针->一个来自类B, 一个来自类C 总大小sizeof(void*)+sizeof(void*)=16
(2)计算类B的成员变量: 大小是sizeof(char b)=1, 但是扩展成4
(3)计算类C的成员变量: 大小是sizeof(char c1) + sizeof(char c2)=2, 但是扩展成4
(4)计算类D的成员变量: 大小是sizeof(int d) = 4, 但是类D中有虚表(所以应该按照8对齐), 扩展成8
所以最终结果是16+4+4+8 = 32
在情景2计算类D大小的步骤:
(1)计算虚表指针: 类D中一共有两个虚表指针->一个来自类B, 一个来自类C 总大小sizeof(void*)+sizeof(void*)=16
(2)计算类B的成员变量: 没有
(3)计算类C的成员变量: 没有
(4)计算类D的成员变量: sizeof(char b) + sizeof(char c1) + sizeof(char c2) = 3 因为后面是跟着一个int,所以这里扩展成4;
sizeof(int d)=4;
所以大小是16+4+4 = 24. 因为24是8的倍数所以24就是最终结果.
可以看到,两种情景计算大小时候虚表放在最终派生类计算, 基类则相当于在没有虚表的情况下去计算本基类的大小,而派生类计算大小时候不考虑基类的成员变量.但是最终结果就是基类大小+派生类大小
第一个程序因为b c1 c2都不满4字节,和虚表存在对齐的内存浪费。
结果就是B C各自占了16字节。
第二个程序B C则各自占了8个字节。
你可以测试下面代码
class C{
public:
//char c1;
//char c2;
virtual void c1x(){}
virtual void c2x(){}
};
然后打开那两行注释
你会发现sizeof(C)在没有任何变量的时候是8,1个char 2个char都是16
你把类D的对象加起来就行了啊,二里面多了个需要对齐的4位。