这里是一些资料:
详细的参看《C++对象模型》
C++98标准规定的类存储空间如下:
1.出于执行效率的考虑,所有的成员函数都在编译时期转换为普通函数,所以不占运行期类内存空间;
2.非静态成员,根据数据类型分配相应空间,顺序不确定,目前大部分编译器都按声明顺序分配;
静态成员,在全局数据区,不占类存储空间。
3.存在虚函数的,由于虚函数是运行期绑定,必须分配运行期内存空间,考虑提高存储空间,采用统一的虚函数表
存储该类的所有虚函数,而所有类对象会添加一个指向该表的指针vptr;
4.存在继承关系,派生类会增加基类的存储空间(不是全部可见);
5.如果是虚继承,则会在派生类增加虚基类的索引指针,保证只有一份拷贝;
6.空间对齐,处于硬件处理效率的考虑(最大化数据通路传输能力)#pragma pack(n),一般32位处理器,n=4;
但是空类不作对齐处理,会增加一个char成员,即为1Byte,目的是为了区分不同空类对象;
来自:http://blog.youkuaiyun.com/freshgamer/archive/2010/05/09/5573063.aspx
下面给出一些测试的代码:
#include "stdafx.h"
#include <iostream>
using std::cout;
using std::endl;
1、无继承
输出结果:
the value of bird size is::8
the value of &bird is::0x13FF5C
the value of &(bird.m_type) is::0x13FF5C
the value of &(bird.m_weight) is::0x13FF60
2、单继承无虚函数
输出结果:
the value of bird size is::16
the value of &bird is::0x13FF54
the value of &(bird.m_Life0No) is::0x13FF54
the value of &(bird.m_Life0Zone) is::0x13FF58
the value of &(bird.m_type) is::0x13FF5C
the value of &(bird.m_weight) is::0x13FF60
3、单继承有虚函数
输出结果:
the value of bird size is::20
the value of &bird is::0x13FF50
the value of &(bird.m_Life0No) is::0x13FF54
the value of &(bird.m_Life0Zone) is::0x13FF58
the value of &(bird.m_type) is::0x13FF5C
the value of &(bird.m_weight) is::0x13FF60
4、单虚继承无虚函数
输出结果:
the value of bird size is::20
the value of &bird is::0x13FF50
the value of &(bird.m_Life0No) is::0x13FF5C
the value of &(bird.m_Life0Zone) is::0x13FF60
the value of &(bird.m_type) is::0x13FF54
the value of &(bird.m_weight) is::0x13FF58
5、单虚继承有虚函数
输出结果:
the value of bird size is::24
the value of &bird is::0x13FF4C
the value of &(bird.m_Life0No) is::0x13FF5C
the value of &(bird.m_Life0Zone) is::0x13FF60
the value of &(bird.m_type) is::0x13FF50
the value of &(bird.m_weight) is::0x13FF54
6、分析
| 无继承 | 单继承 无虚函数 | 单继承 有虚函数 | 单虚继承 无虚函数 | 单虚继承 有虚函数 |
bird size | 8 | 16 | 20 | 20 | 24 |
&bird | 0x13FF5C | 0x13FF54 | 0x13FF50 | 0x13FF50 | 0x13FF4C |
&(bird.m_Life0No) |
| 0x13FF54 | 0x13FF54 | 0x13FF5C | 0x13FF5C |
&(bird.m_Life0Zone) |
| 0x13FF58 | 0x13FF58 | 0x13FF60 | 0x13FF60 |
&(bird.m_type) | 0x13FF5C | 0x13FF5C | 0x13FF5C | 0x13FF54 | 0x13FF50 |
&(bird.m_weight) | 0x13FF60 | 0x13FF60 | 0x13FF60 | 0x13FF58 | 0x13FF54 |
分析结果 | 对象地址= m_type的地址 | 对象地址= m_Life0No的地址 | 对象地址= 指向虚函数表的指针的地址 | 对象地址= 0x13FF50应该是虚基类的索引指针 | 对象地址= 0x13FF4C(我分不清楚 0x13FF4C和 0x13FF58,哪个是虚基类的索引指针,哪个是指向虚函数表的指针的地址) |
分结论 | 1、对象的地址是第一个声明的非静态成员变量的地址 2、非静态成员变量声明越靠后地址值越大 | 1、对象地址是父类中第一个声明的非静态成员变量的地址 2、父类中的任一非静态成员变量的地址小于子类中任一非静态成员变量地址 3、父类(或者子类)非静态成员变量声明越靠后地址值越大。 | 1、对象地址是指向虚函数表的指针的地址 2、父类中的任一非静态成员变量的地址小于子类中任一非静态成员变量地址 3、父类(或者子类)非静态成员变量声明越靠后地址值越大。 | 1、对象地址是虚基类的索引指针 2、父类中的任一非静态成员变量的地址大于子类中任一非静态成员变量地址 3、父类(或者子类)非静态成员变量声明越靠后地址值越大。 | 1、对象地址是最小的地址 2、父类中的任一非静态成员变量的地址大于子类中任一非静态成员变量地址 3、父类(或者子类)非静态成员变量声明越靠后地址值越大。 |
总结论 | 1、对象的地址是该对象拥有的所有地址中的最小地址; 2、每个类中的非静态成员变量的声明顺序将会决定其地址值的大小,声明越靠后,地址值越大; 3、继承和虚继承会影响父类和子类地址的分配顺序; 4、以上的前提条件是在VS2008环境、无空类、无静态成员变量的情况下测试出来的; |