类/对象大小计算
来源:互联网 发布:源码大师咋用 编辑:程序博客网 时间:2024/06/05 20:44
1,类大小计算遵循结构体对齐原则
什么是内存对齐
编译器为每个“数据单元”按排在某个合适的位置上。
C、C++语言非常灵活,它允许你干涉“内存对齐”
为什么要对齐
性能原因:在对齐的地址上访问数据快。
如何对齐
第一个数据成员放在offset为0的位置
其它成员对齐至min(sizeof(member),#pragma pack(n)所指定的值)的整数倍。
整个结构体也要对齐,结构体总大小对齐至各个成员中最大对齐数的整数倍。
举个例子,
struct test
{char a;
double b;
char c;
};
根据规则1,a 在位置0;根据规则2,因为VC默认pack为8,可以通过项目-》属性-》c/c++ -》代码生成-》结构体成员对齐选项修改,也可以使用#pragma pack(n) 来修改,#pragma pack() 取消修改,那么b 占据8~15;根据规则2,c在16;现在总共17个字节,根据规则3,结构体总大小需对齐到8的整数倍,即总共是24个字节。
如果将pack 修改为4,则总大小为16。在VC上pack 共有1,2,4,8,16 等5种选择,而linux g++ 则只有1,2,4 可选,默认是4。
2,类的大小与数据成员有关与成员函数无关(空类大小为1个字节),类的大小与静态数据成员无关。
3,虚函数、虚继承对类的大小的影响
第一个数据成员放在offset为0的位置
其它成员对齐至min(sizeof(member),#pragma pack(n)所指定的值)的整数倍。
整个结构体也要对齐,结构体总大小对齐至各个成员中最大对齐数的整数倍。
类的大小与静态数据成员无关
虚继承对类的大小的影响
虚函数对类的大小的影响
下面通过实例来展示虚继承和虚函数对类大小造成的影响。
测试环境为:Win32 + Vs2008
一、只出现虚继承的情况
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
using namespace std;
class BB
{
public :
int bb_ ;
};
class B1 : virtual public BB
{
public :
int b1_ ;
};
class B2 : virtual public BB
{
public :
int b2_ ;
};
class DD : public B1, public B2
{
public :
int dd_ ;
};
int main (void)
{
cout<<sizeof (BB)<< endl;
cout<<sizeof (B1)<< endl;
cout<<sizeof (DD)<< endl;
B1 b1 ;
int** p ;
cout<<&b1 <<endl;
cout<<&b1 .bb_<< endl;
cout<<&b1 .b1_<< endl;
p = (int **)&b1;
cout<<p [0][0]<<endl;
cout<<p [0][1]<<endl;
DD dd ;
cout<<&dd <<endl;
cout<<&dd .bb_<< endl;
cout<<&dd .b1_<< endl;
cout<<&dd .b2_<< endl;
cout<<&dd .dd_<< endl;
p = (int **)ⅆ
cout<<p [0][0]<<endl;
cout<<p [0][1]<<endl;
cout<<endl ;
cout<<p [2][0]<<endl;
cout<<p [2][1]<<endl;
BB* pp ;
pp = &dd ;
dd.bb_ = 10; //对象的内存模型在编译时就已经确定了,否则无法定义类的对象,因为要开辟内存
int base = pp-> bb_; // 通过间接访问 (其实pp 已经偏移了20 ),这需要运行时的支持
cout<<"dd.bb_=" <<base<< endl;
return 0;
}
从输出的地址和虚基类表成员数据可以画出对象内存模型图:
virtual base table
本类地址与虚基类表指针地址的差
虚基类地址与虚基类表指针地址的差
virtual base table pointer(vbptr)
从程序可以看出pp是BB* 指针,pp首先指向dd内存,当执行pp->bb_时,先找到首个vbptr,找到虚基类BB地址与虚基类表指针地址的差,也即是20,接着pp偏移20个字节指向了dd对象中的BB部分,然后就访问到了bb_,这是在运行时才做的转换。
二、只出现虚函数的情况
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
using namespace std;
class Base
{
public :
virtual void Fun1()
{
cout << "Base::Fun1 ..." << endl;
}
virtual void Fun2()
{
cout << "Base::Fun2 ..." << endl;
}
int data1_ ;
};
class Derived : public Base
{
public :
void Fun2 ()
{
cout << "Derived::Fun2 ..." << endl;
}
virtual void Fun3()
{
cout << "Derived::Fun3 ..." << endl;
}
int data2_ ;
};
typedef void (* FUNC)(void );
int main (void)
{
cout << sizeof (Base) << endl;
cout << sizeof (Derived) << endl;
Base b ;
int **p = (int **)& b;
FUNC fun = (FUNC) p[0][0];
fun();
fun = (FUNC )p[0][1];
fun();
cout << endl ;
Derived d ;
p = (int **)&d;
fun = (FUNC )p[0][0];
fun();
fun = (FUNC )p[0][1];
fun();
fun = (FUNC )p[0][2];
fun();
return 0;
}
从输出的函数体可以画出对象内存模型图:
vtbl:虚函数表(存放虚函数的函数指针)
vptr:虚函数表指针
从输出可以看出,Derived类继承了Base::Fun1,而覆盖了Fun2,此外还有自己的Fun3。注意,因为Fun3是虚函数,才会出现在虚函数表,如果是一般函数是不会的,因为不用通过vptr间接访问。
三、虚继承与虚函数同时出现的情况:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
using namespace std;
class BB
{
public :
virtual void vfbb()
{
cout<<"BB::vfbb" <<endl;
}
virtual void vfbb2()
{
cout<<"BB::vfbb2" <<endl;
}
int bb_ ;
};
class B1 : virtual public BB
{
public :
virtual void vfb1()
{
cout<<"B1::vfb1" <<endl;
}
int b1_ ;
};
class B2 : virtual public BB
{
public :
virtual void vfb2()
{
cout<<"B2::vfb2" <<endl;
}
int b2_ ;
};
class DD : public B1, public B2
{
public :
virtual void vfdd()
{
cout<<"DD::vfdd" <<endl;
}
int dd_ ;
};
typedef void (* FUNC)(void);
int main (void)
{
cout<<sizeof (BB)<< endl;
cout<<sizeof (B1)<< endl;
cout<<sizeof (DD)<< endl;
BB bb ;
int** p ;
p = (int **)&bb;
FUNC fun ;
fun = (FUNC )p[0][0];
fun();
fun = (FUNC )p[0][1];
fun();
cout<<endl ;
B1 b1 ;
p = (int **)&b1;
fun = (FUNC )p[0][0];
fun();
fun = (FUNC )p[3][0];
fun();
fun = (FUNC )p[3][1];
fun();
cout<<p [1][0]<<endl;
cout<<p [1][1]<<endl;
cout<<endl ;
DD dd ;
p = (int **)ⅆ
fun = (FUNC )p[0][0];
fun();
fun = (FUNC )p[0][1]; // DD::vfdd 挂在 B1::vfb1的下面
fun();
fun = (FUNC )p[3][0];
fun();
fun = (FUNC )p[7][0];
fun();
fun = (FUNC )p[7][1];
fun();
cout<<p [1][0]<<endl;
cout<<p [1][1]<<endl;
cout<<p [4][0]<<endl;
cout<<p [4][1]<<endl;
return 0;
}
从输出的虚基类表成员数据和虚函数体可以画出对象内存模型图:
- 类/对象大小计算
- 类/对象大小的计算
- 类对象大小的 sizeof 计算问题
- 计算对象大小
- C++类对象大小的计算(一)常规类大小计算
- C++类对象大小的计算(二)含有虚函数类大小计算
- C++类对象大小的计算(三)含有虚函数、虚继承类大小计算
- 关于类对象大小的 sizeof 计算问题
- 关于类对象大小的 sizeof 计算问题(续)
- 关于类对象大小的 sizeof 计算问题
- 关于类对象大小的 sizeof 计算问题
- 08-15 关于类对象大小的 sizeof 计算问题 .
- 使用sizeof计算类对象所占空间大小
- 关于类对象大小的 sizeof 计算问题
- 使用 sizeof 计算类对象所占空间大小
- 类的大小计算
- 类大小的计算
- 类大小的计算
- 拿什么来拯救自己
- java设计模式---原型模式
- PendingIntent详解
- 敢想敢做,执着追求才能超越极致!------ 我的mslist之mslist.h
- Aspose进军Android市场 发布多款Android产品
- 类/对象大小计算
- Photoshop----色彩原理和图层的混合模式
- java-类型通配符
- 不用命令玩转Ubuntu(Wubi图文教程)
- 使用命名管道的OVERLAPPED方式实现非阻塞模式编程 .
- ubuntu 挂载u 盘
- Windows 7下安装配置PHP+Apache+Mysql环境教程
- 【转】生命中的最后一天
- 黑马程序员--06.基本数据类型的包装类--【Integer类】【字符串和基本数据类型的包装类】