帖子 http://topic.csdn.net/u/20071110/22/9c60e7a4-2de7-452a-98ad-fb449f428286.html?seed=888299228
#include <iostream>
using namespace std;
class A
{
double a;
char b;
virtual p(){};
};
void main()
{
cout < <sizeof(A) < <endl;
}
强人回帖如下:
对于这个问题:首先说明一下不带虚函数时候的情况,其分配规则为:
VC对一些变量的起始地址做了“对齐”处理。在默认情况下,VC规定 1.各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式(vc6.0,32位系统)。
类型 对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
Char 偏移量必须为sizeof(char)即1的倍数
Short 偏移量必须为sizeof(short)即2的倍数
int 偏移量必须为sizeof(int)即4的倍数
float 偏移量必须为sizeof(float)即4的倍数
double 偏移量必须为sizeof(double)即8的倍数
各成员变量在存放的时候根据在 结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节VC会自动填充。同时 2.VC为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
===========================
上面红色的部分是两条主要的规则。而绿色的部分是解决这个问题的关键。
代码实例1
对于你的问题,我们把最后的虚函数改为int ;根据规则1,a占8个字节,b占1个字节,而后c要根据规则1对齐,所以b后面会有3个字节被填充掉,c从b后的第4个字节开始。它占4个,最后结果是:8+(1+3)+4=16。同时符合了规则2。所以为16。
用图表示为:
--
a 8个字节
---
b 一个字节
----
三个填充字节
-----
c 四个字节
---
那么现在请注意 上面文字中的绿色部分。我们改变一下顺序。
代码实例2
那么开始的c占4个字节,根据规则1,a在分配之前,c和a之间的距离应该为8,即c后面有4个空间需要被填充。对于b,其占一个字节。所以最后是(4+4)+8+1=17;根据规则2,整个类要是8的倍数,所以b后面会再填充7个,即17+7=24。
图示:
----
c 四个字节
----
4个填充
----
a 八个字节
---
b 一个字节
----
七个填充字节
------
接下来是本帖的解答:
既然虚函数指针也是4个字节,那么结果为什么不是16呢?而是24呢。?
因为在分配空间的时候,其顺序是先分配虚函数表指针,然后才是变量的。所以虚函数在类中的位置对类的大小无影响,其始终是在最前面的。
用图实例:
----
vptable 4个字节
-------
4个填充
-----
a 八个
-----
b 一个
-----
7个填充。。
==========
总结:本帖的关键是虚函数表指针不是按照它在类中出现的顺序分配的,而是总是首先被分配的。你可以把他放到类中的其他位置,做实验,始终是24。。。。
后又跟帖
我纠正一下,对于普通成员变量。我上面的说法是正确的。但涉及到虚函数。我的解释有些失误。向大家道歉。
当有虚函数的时候。
比如楼主提供的这段代码。其存储形式 类似表示为:(注明:vc6的编译器)
你可以分析上面的这段代码,按照普通变量的规则 。里面的类为16个字节。最大对齐字节是8。所以p指针的存储空间按照最大的存储,为8。。所以总共为24。
=====
据说涉及到虚函数表指针的问题。都很麻烦。。汗。。
#include <iostream>
using namespace std;
class A
{
double a;
char b;
virtual p(){};
};
void main()
{
cout < <sizeof(A) < <endl;
}
强人回帖如下:
对于这个问题:首先说明一下不带虚函数时候的情况,其分配规则为:
VC对一些变量的起始地址做了“对齐”处理。在默认情况下,VC规定 1.各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式(vc6.0,32位系统)。
类型 对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
Char 偏移量必须为sizeof(char)即1的倍数
Short 偏移量必须为sizeof(short)即2的倍数
int 偏移量必须为sizeof(int)即4的倍数
float 偏移量必须为sizeof(float)即4的倍数
double 偏移量必须为sizeof(double)即8的倍数
各成员变量在存放的时候根据在 结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节VC会自动填充。同时 2.VC为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
===========================
上面红色的部分是两条主要的规则。而绿色的部分是解决这个问题的关键。
代码实例1
-
C/C++ code
-
#include < iostream >
using namespace std;
class A
{
double a;
char b;
int c;
};
void main()
{
cout < < sizeof (A) < < endl;
}
对于你的问题,我们把最后的虚函数改为int ;根据规则1,a占8个字节,b占1个字节,而后c要根据规则1对齐,所以b后面会有3个字节被填充掉,c从b后的第4个字节开始。它占4个,最后结果是:8+(1+3)+4=16。同时符合了规则2。所以为16。
用图表示为:
--
a 8个字节
---
b 一个字节
----
三个填充字节
-----
c 四个字节
---
那么现在请注意 上面文字中的绿色部分。我们改变一下顺序。
代码实例2
-
C/C++ code
-
#include < iostream >
using namespace std;
class A
{
int c;
double a;
char b;
};
void main()
{
cout < < sizeof (A) < < endl;
}
那么开始的c占4个字节,根据规则1,a在分配之前,c和a之间的距离应该为8,即c后面有4个空间需要被填充。对于b,其占一个字节。所以最后是(4+4)+8+1=17;根据规则2,整个类要是8的倍数,所以b后面会再填充7个,即17+7=24。
图示:
----
c 四个字节
----
4个填充
----
a 八个字节
---
b 一个字节
----
七个填充字节
------
接下来是本帖的解答:
既然虚函数指针也是4个字节,那么结果为什么不是16呢?而是24呢。?
因为在分配空间的时候,其顺序是先分配虚函数表指针,然后才是变量的。所以虚函数在类中的位置对类的大小无影响,其始终是在最前面的。
用图实例:
----
vptable 4个字节
-------
4个填充
-----
a 八个
-----
b 一个
-----
7个填充。。
==========
总结:本帖的关键是虚函数表指针不是按照它在类中出现的顺序分配的,而是总是首先被分配的。你可以把他放到类中的其他位置,做实验,始终是24。。。。
后又跟帖
我纠正一下,对于普通成员变量。我上面的说法是正确的。但涉及到虚函数。我的解释有些失误。向大家道歉。
当有虚函数的时候。
-
C/C++ code
-
#include < iostream >
using namespace std;
class A
{
double a;
char b;
virtual p(){};
};
void main()
{
cout < < sizeof (A) < < endl;
}
比如楼主提供的这段代码。其存储形式 类似表示为:(注明:vc6的编译器)
-
C/C++ code
-
class A
{
[color = #FF0000] void [ / color] * p; // 虚函数表指针
class {
public :
char b;
double a;
}; -
-
向牛人学习,向牛人致敬!
};
你可以分析上面的这段代码,按照普通变量的规则 。里面的类为16个字节。最大对齐字节是8。所以p指针的存储空间按照最大的存储,为8。。所以总共为24。
=====
据说涉及到虚函数表指针的问题。都很麻烦。。汗。。