类中内容在内存中到底是如何分配的呢?
分类:
一个类,有成员变量:静态与非静态之分;而成员函数有三种:静态的、非静态的、虚的。
那么这些个东西在内存中到底是如何分配的呢?
以一个例子来说明:
[html]view plaincopyprint?
- #include"iostream.h"
- class CObject
- {
- public:
- static int a;
- CObject();
- ~CObject();
- void Fun();
- private:
- int m_count;
- int m_index;
- };
- void CObject::Fun()
- {
- cout<<"Fun\n"<<endl;
- }
- CObject::CObject()
- {
- cout<<"Construct!\n";
- }
- CObject::~CObject()
- {
- cout<<"Destruct!\n";
- }
- int CObject::a=1;
- void main()
- {
- cout<<"Sizeof(CObject):"<<sizeof(CObject)<<endl;
- //CObject::Fun();
- cout<<"CObject::a="<<CObject::a<<endl;
- CObject myObject;
- cout<<"sizeof(myObject):"<<sizeof(myObject)<<endl;
- cout<<"sizeof(int)"<<sizeof(int)<<endl;
- }
这是我的一段测试代码,
运行结果是:
Sizeof(CObject):8
CObject::a=1
Construct!
sizeof(myObject):8
sizeof(int)4
Destruct!
我有疑问如下:
(1) C++中,应该是对象才会被分配内存空间吧??为什么CObject内存大小是8,刚好和两个 成员变量的大小之和一致!难道还没实例化的时候,类就 已经有了内存空间了?
(2)当对象生成了之后,算出的内存大小怎么还是8,函数难道不占用内存空间吗?至少应该放个 函数指针在里面的吧?内存是怎样布局的?
(3) 静态成员应该是属于类的,怎么类的大小中没有包含静态成员的大小?
下面分别解答如下:
1)Sizeof(CObject)是在编译时就计算了的,一个类定义了,它所占的内存编译器就已经知道了,这时只是得到它占用的大小,并没有分配内存操作 。也可以这样想:编译器肯定知道大小了,这与分配内存空间无关,知道大小了,以后实例化了才能知道要分配多大。
2)类的普通成员、静态成员函数是不占类内存的,至于你说的函数指针在你的类中有 虚函数的时候存在一个 虚函数表指针,也就是说如果你的类里有虚函数则 sizeof(CObject)的值会增加4个字节。
其实 类的成员函数 实际上与 普通的 全局函数一样。
只不过编译器在编译的时候,会在成员函数上加一个参数,传入这个对象的指针。
成员函数地址是全局已知的,对象的内存空间里根本无须保存成员函数地址。
对成员函数(非虚函数)的调用在编译时就确定了。
像 myObject.Fun() 这样的调用会被编译成形如 _CObject_Fun( &myObject ) 的样子。
函数是不算到sizeof中的,因为函数是代码,被各个对象共用,跟数据处理方式不同。对象中不必有函数指针,因为对象没必要知道它的各个函数的地址(调 用函数的是其他代码而不是该对象)。
类的属性是指类的数据成员,他们是实例化一个对象时就为数据成员分配内存了,而且每个对象的数据成员是对立的,而成员函数是共有的~
静态成员函数与一般成员函数的唯一区别就是没有this指针,因此不能访问非静态数据成员。总之,程序中的所有函数都是位于代码区的。
3)静态成员并不属于某个对象,sizeof取的是对象大小。
知道了上面的时候,就可以改一下来看看:
我也补充一些:
class CObject
{
public:
static int a;
CObject();
~CObject();
void Fun();
private:
double m_count; //这里改成了double
int m_index;
};
这个类用sizeof()测出来的大小是 2*sizeof(double)=16
class CObject
{
public:
static int a;
CObject();
~CObject();
void Fun();
private:
char m_count; //这里改成了char
int m_index;
};
大小是2*sizeof(int)=8
class CObject
{
public:
static int a;
CObject();
~CObject();
void Fun();
private:
double m_count; //这里改成了double
int m_index;
char c;
};
sizeof(char)+sizeof(int) <sizeof(double) 所以大小是2*sizeof(double)
其实这里还有一个是内存对齐的问题。
空类大小是1。
另外要注意的一些问题:
先看一个空的类占多少空间?
class Base
{
public:
Base();
~Base();
};
class Base { public: Base(); ~Base(); };
注意到我这里显示声明了构造跟析构,但是sizeof(Base)的结果是1.
因为一个空类也要实例化,所谓类的实例化就是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。同样空类也会被实例化,所以编译器会给空类隐含 的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。
而析构函数,跟构造函数这些成员函数,是跟sizeof无关的,也不难理解因为我们的sizeof是针对实例,而普通成员函数,是针对类体的,一个类的成 员函数,多个实例也共用相同的函数指针,所以自然不能归为实例的大小,这在我的另一篇博文有提到。
接着看下面一段代码
[html]view plaincopyprint?
- class Base
- {
- public:
- Base();
- virtual ~Base(); //每个实例都有虚函数表
- void set_num(int num) // 普通成员函数,为各实例公有,不归入sizeof统计
- {
- a=num;
- }
- private:
- int a; //占4字节
- char *p; //4字节指针
- };
- class Derive:public Base
- {
- public:
- Derive():Base(){};
- ~Derive(){};
- private:
- static int st; //非实例独占
- int d; //占4字节
- char *p; //4字节指针
- };
- int main()
- {
- cout<<sizeof(Base)<<endl;
- cout<<sizeof(Derive)<<endl;
- return 0;
- }
class Base { public: Base(); virtual ~Base(); //每个实例都有虚函数表 void set_num(int num) //普通成员函数,为各实例公有,不归入sizeof统计 { a=num; } private: int a; //占4字节 char *p; //4字节指针 }; class Derive:public Base { public: Derive():Base(){}; ~Derive(){}; private: static int st; //非实例独占 int d; //占4字节 char *p; //4字节指针 }; int main() { cout<<sizeof(Base)<<endl; cout<<sizeof(Derive)<< endl; return 0; }
结果自然是
12
20
Base类里的int a;char *p;占8个字节。
而虚析构函数virtual ~Base();的指针占4子字节。
其他成员函数不归入sizeof统计。
Derive类首先要具有Base类的部分,也就是占12字节。
int d;char *p;占8字节
static int st;不归入sizeof统计
所以一共是20字节。
在考虑在Derive里加一个成员char c;
- class Derive:public Base
- {
- public:
- Derive():Base(){};
- ~Derive(){};
- private:
- static int st;
- int d;
- char *p;
- char c;
- };
class Derive:public Base { public: Derive():Base(){}; ~Derive(){}; private: static int st; int d; char *p; char c; };
这个时候,结果就变成了
12
24
一个char c;增加了4字节,说明类的大小也遵守类似class字节对齐,的补齐规则。
具体的可以看我那篇《5分钟搞定字节对齐》
至此,我们可以归纳以下几个原则:
1.类的大小为类的非静态成员数据的类型大小之和,也 就是说静态成员数据不作考虑。
2.普通成员函数与sizeof无关。
3.虚函数由于要维护在虚函数表,所以要占据一个指针大小,也就是4字节。
4.类的总大小也遵守类似class字节对齐的,调整规则。
转载自:http://www.blue1000.com/bkhtml/c151/2010-11/69613.htm
类中内容在内存中到底是如何分配的呢?相关推荐
- JavaScript中数据在内存中的存储方式
JavaScript中数据在内存中的存储方式 1.js数据类型分类 简单数据类型:Number.String.Boolean.Undefined.Null 复杂数据类型:Object.Array.Fu ...
- C语言中变量在内存中是如何存放的
首先我们知道计算机有32位/64位,那这里的32位/64位代表什么意思呢? 其实这里的32位/63位代表地址线,如果你的电脑是32位的,就是地址总线宽度为32位,一次可以发送的一个数据是32位的,则寻 ...
- c语言中小数在内存中的存储,c语言中小数在内存中的存储
转至:https://blog..net/tqs_1220/article/details/73550899 首先看float和double在内存中是怎么存储的? float:符号位(1位)+指数位( ...
- 解析C语言中数据在内存中的存储
系列文章目录 文章目录 系列文章目录 前言 一.数据类型介绍 1.类型的基本归类 1.整形家族 2.浮点型家族 3.构造类型 4.指针类型 5.空类型 二.整型在内存中的存储 1.原码.反码.补码 2 ...
- C语言中数据在内存中的存储
要想了解数据在内存中的存储的话,首先应该了解数据的类型. 下面介绍C语言中数据类型: 1.C语言中的基本内置类型: char //字符数据类型 大小为1个字节 short //短整型 大小为2个字节 ...
- java python 运行 内存_Python C Java中字符串在内存中的存储
Python 昨天在讲Python的过程中,发现了一个小问题,当时课上没有解决,下面特意查阅资料解决了一下. a = "123" b = "123" print ...
- Java中数组在内存中的存放原理?
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangyong0717/article/details/79165685 Java中数组被实现为对象 ...
- Proteus中查看C51内存中变量的值 寄存器的值
在调试状态下,调试选项卡中选择CPU 第一个是寄存器 第二个详见(SFR) 基础讲解: http://www.21ic.com/jichuzhishi/mcu/memory/2013-04-19/17 ...
- linux复制文件中内容吗,Linux中实现对文件内容的复制。。。
//linux学习路上的初学者 //使用前你需要先创建好两个文件 1.txt 2.txt 并在1.txt里面写好内容. #include#include#include#include#include ...
最新文章
- Linux Linux程序练习十一(网络编程大文件发送UDP版)
- DeepMind 综述深度强化学习:智能体和人类相似度竟然如此高!
- VC++ 实现自定义消息
- spring boot中使用Pagehelper实现分页
- 「LibreOJ Round #11」Misaka Network 与测试 (网络流跑二分图匹配)
- Awesome Tools Site
- sublime text3安装插件 emmet
- pgsql中float4导致java程序精度丢失_Java基础系列02
- java 存储过程返回结果集_通过SQL“select * from”从java存储过程返回结果集
- mysql 参数 innodb_flush_log_at_trx_commit
- notepad格式化html代码快捷键,Notepad++中代码格式化插件NppAStyle使用介绍
- c++学习笔记(八)- map
- springboot 腾讯云短信平台SDK
- JVM--基础--19.4--垃圾收集器--Parallel Scavenge
- 视觉SLAM十四讲笔记-第四讲 李群与李代数
- 从杉数到滴滴——未入门算法工程师工作日记(快手篇)
- 直流无刷电机【一】从零开始上手
- B-树和B+树的区别
- 力扣算法学习计划打卡:第八天
- Leetcode 13 罗马数字转整数数字
热门文章
- android 版本权限差别,android apk 的root 权限和USB adb 权限的区别
- TIMING_04 时序约束的一般步骤
- c++判断整数翻转溢出_LeetCode7.整数反转(Reverse Integer)
- 项目管理excel_项目经理必备的6款项目管理软件
- python天天向上每十天休息一天_Python基础第十天
- 见识可能比聪明更重要!
- 三极管和MOS管有什么不一样?用MOS管还是三极管?
- DIY一只机器狗需要多少钱?最低仅900美元,斯坦福大学出品,代码已开源
- html 判断当前窗口是否是子窗口,C#的MDI窗体判断子窗体是否已经打开
- lrange是取出所有值并移除么_美欧日站点亚马逊物流库存绩效指标分数达标值将降低为 450...