类的构造(2):对象的内存布局
来源:互联网 发布:手机上解压软件 编辑:程序博客网 时间:2024/06/01 20:24
一个类对象在内存中总占几个字节,哪些内容分别占多少字节呢? 我们举个例子来瞧下.
//由于存在啥内存对齐,所以你用sizeof去检查类的size时会不准确.所以这里使用个#pragma pack(1)显式指定内存对齐模式会使结果比较准确点.
//内存对齐详细解释见http://baike.baidu.com/view/4786260.htm
简单示例1:静态变量,函数不占用类对象内存
#pragma pack(1)
class human{
int ID; //占4个字节
char ch; //占1字节
static int age; //占4字节
};
class father : public human{
void Test();
};
void main()
{
cout<< sizeof human; //大小为5,而不是你期望的9,因为static型的成员变量不属于类对象,它是放在静态存储区里面去了.
cout<<sizeof father ; //大小也是5,把human中的内容原封不动的拷贝一份放到father里面来的.要是类比下嘛,跟头文件类似,引用头文件时实际上相当于把所有内容复制过来.
//当然只是类似,有时是原封不动拷,但有时只是选择性的拷贝的.
//我们看到函数是不占用类对象的内存的,函数是放到代码区.
}
示例2:虚函数的的特殊处理
假如类中有虚函数那么类对象中会额外隐式添加一个指针,指向一个虚拟函数表.
class human{
int ID; //4字节
char ch; //1字节
virtual void Test();
}
cout<<sizeof human; //大小为9,这里假设是32位系统,一个指针占4字节.
你可能会问那么虚拟函数表是啥东东啊?怎么实现的啊.
具体怎么实现的我也不清楚,没看到过相关资料.不过我们可以从MFC构架的一些思想里猜想下.MFC中最爱干的事就是在类中整一堆宏嘛,来实现啥动态类型识别,动态创建之类的.实际上就是在类中声明一个static的结构体CRuntimeClass,把相关信息都放这结构体里.
那我们这里来猜想下,类human中可能会这样写
class human{
int ID;
char ch;
virtual void Test();
static list<FunNode> funList; //这里就简化处理了,一个链表,每个节点是个函数指针.比如可以添加节点funList.add(Test);
list<FunNode>* vptr; //指向上面那个funList的指针.所以有虚函数时多出的4个字节内存就是它了.不管有多少个虚函数也只多它一个指针
}
那假如有类father继承类human会怎么样呢?
father会创建自己的虚函数表,只不过会把human中虚函数表内容拷过来.然后创建一个指针vptr指向自己创建的虚函数表.
示例3:虚拟继承
我们知道多重继承中,有个典型的缺陷就是会有歧义产生,而解决办法就是用虚拟继承.示例
非虚拟继承
class human{
public:
int ID; //4字节
char ch; //1字节
};
class father: public human{
};
class mather: public human{
};
class son: public father, public mather{
};
cout<<sizeof human; //5字节
cout<<sizeof father <<sizeof mather; //都是5字节
cout<<sizeof son; //10字节father与mather的和嘛
上面的内存布局很好理解,father和mather拷贝一份human的内容.而son又把father与mather的拷贝过来.
我们知道如果father与mather的继承中如果不加virutal这关键字的话,则这样使用会报错: Son so;
int num = so.ID; //因为son中有从father拷过的ID,也有从mather拷来的ID,编译器不知道去找哪个了.不过你可以这样显式的调用
int num = so.father::ID;//或者so.mather::ID;
虚拟继承
当然上面这样做很麻烦,所以有这样一个解决方法
class father: public virtual human{
};
class mather: public virtual human{
};
上面其他不变,只是加上virtaul关键字.
cout<<sizeof human; //仍为5
cout<<sizeof father<<sizeof mather; //都为9
cout<<sizeof son<<为13
这个结果有点不可思议吧.
当使用虚拟继承之后,father除了拷贝human中的5个字节外还增加一个指针(4字节),指向human的指针.所以大小为9
而son是先从human中拷贝5字节过来,然后拷贝father中非human的部分4字节,拷贝mather中非human的部分4字节.所以加起来是13.
假如father中还另外定义个成员,比如int money; //则son也还拷过来.这样会在13基础上再加4.
反正记住的一点就是human的在father,mather中会拷去两份相同的内容.而son只会拷一份过来.当然为了保证这个操作额外的代价是多出些指针来了啊.
- 类的构造(2):对象的内存布局
- 对象的内存布局
- 对象的内存布局
- 对象的内存布局
- 对象的内存布局
- 对象的内存布局
- 类的内存布局-sizeof(类对象)
- 普通类对象的内存布局
- MSVC查看类的对象内存布局
- c++ 对象的内存布局
- C++ 对象的内存布局
- C++ 对象的内存布局
- C++ 对象的内存布局
- C++ 对象的内存布局
- C++ 对象的内存布局
- C++ 对象的内存布局
- 浅谈对象的内存布局
- C++ 对象的内存布局
- z-stack初始化物理地址
- ubuntu12.10安装交叉编译器arm-none-linux-gnueabi-gcc
- z-stack halprocesspoll与初始化
- Structs学习
- matlab中semilogx画图和显示errorbar ‘工’字型误差
- 类的构造(2):对象的内存布局
- 关于MySQL的自增
- OD使用教程2 解密系列之调试篇02
- UAAP解决方案小记(一)
- 线程中拷贝文件前没有sleep,拷贝失败
- JSP页面中导出Excel文件及其中文乱码的解决办法
- Hdu 4515 小Q系列故事——世界上最遥远的距离 (日期模拟)
- UVa 673 - Parentheses Balance
- php 中在数组中添加新元素的方法