全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

浅谈C++ 类的实例中 内存分配详解

一个类,有成员变量:静态与非静态之分;而成员函数有三种:静态的、非静态的、虚的。

那么这些个东西在内存中到底是如何分配的呢?

以一个例子来说明:

#include"iostream.h"
class CObject
{
public:
  static int a;
  CObject();
  ~CObject();
  void Fun();
private: 
int m_count; 
int m_index;
};
VoidCObject::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; 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是针对实例,而普通成员函数,是针对类体的,一个类的成 员函数,多个实例也共用相同的函数指针,所以自然不能归为实例的大小,这在我的另一篇博文有提到。

接着看下面一段代码

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) { a=num; } //普通成员函数,为各实例公有,不归入sizeof统计
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字节对齐,补齐规则。

至此,我们可以归纳以下几个原则:

1.类的大小为类的非静态成员数据的类型大小之和,也就是说静态成员数据不作考虑。

2.普通成员函数与sizeof无关。

以上就是小编为大家带来的浅谈C++ 类的实例中 内存分配详解全部内容了,希望大家多多支持~


# c  # 内存分配  # C++中关键字Struct和Class的区别  # c++中typename和class的区别介绍  # 深入C++中struct与class的区别分析  # C++调试追踪class成员变量的方法  # 浅谈C++内存分配及变长数组的动态分配  # C++动态内存分配(new/new[]和delete/delete[])详解  # 基于C++内存分配、函数调用与返回值的深入分析  # c++ class中成员与分配内存的问题详解  # 都有  # 的是  # 时就  # 改成了  # 里加  # 应该是  # 都是  # 无二  # 这是  # 也就是说  # 知道了  # 我也  # 几个  # 是在  # 还没  # 也会  # 结果是  # 多个  # 也要  # 我有 


相关文章: 小米网站链接制作教程,请问miui新增网页链接调用服务有什么用啊?  如何通过虚拟主机快速搭建个人网站?  车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?  广州美橙建站如何快速搭建多端合一网站?  建设网站制作价格,怎样建立自己的公司网站?  装修招标网站设计制作流程,装修招标流程?  建站DNS解析失败?如何正确配置域名服务器?  建站之星安装提示数据库无法连接如何解决?  头像制作网站在线制作软件,dw网页背景图像怎么设置?  如何用PHP工具快速搭建高效网站?  黑客如何利用漏洞与弱口令入侵网站服务器?  南宁网站建设制作定制,南宁网站建设可以定制吗?  洛阳网站制作公司有哪些,洛阳的招聘网站都有哪些?  SAX解析器是什么,它与DOM在处理大型XML文件时有何不同?  ,巨量百应是干嘛的?  建站上传速度慢?如何优化加速网站加载效率?  建站之星后台密码遗忘如何找回?  c# 在ASP.NET Core中管理和取消后台任务  如何正确选择百度移动适配建站域名?  Python路径拼接规范_跨平台处理说明【指导】  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  如何在景安服务器上快速搭建个人网站?  如何通过西部数码建站助手快速创建专业网站?  微网站制作教程,我微信里的网站怎么才能复制到浏览器里?  定制建站方案优化指南:企业官网开发与建站费用解析  微课制作网站有哪些,微课网怎么进?  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  网站图片在线制作软件,怎么在图片上做链接?  如何在Windows环境下新建FTP站点并设置权限?  建站主机选择指南:服务器配置与SEO优化实战技巧  沈阳制作网站公司排名,沈阳装饰协会官方网站?  为什么Go需要go mod文件_Go go mod文件作用说明  建站中国必看指南:CMS建站系统+手机网站搭建核心技巧解析  如何基于PHP生成高效IDC网络公司建站源码?  东莞市网站制作公司有哪些,东莞找工作用什么网站好?  简历在线制作网站免费版,如何创建个人简历?  如何制作算命网站,怎么注册算命网站?  专业网站制作企业网站,如何制作一个企业网站,建设网站的基本步骤有哪些?  郑州企业网站制作公司,郑州招聘网站有哪些?  建站上市公司网站建设方案与SEO优化服务定制指南  阿里云网站搭建费用解析:服务器价格与建站成本优化指南  如何在Golang中使用replace替换模块_指定本地或远程路径  建站主机如何选?性能与价格怎样平衡?  学校免费自助建站系统:智能生成+拖拽设计+多端适配  微网站制作教程,不会写代码,不会编程,怎么样建自己的网站?  制作网站的过程怎么写,用凡科建站如何制作自己的网站?  如何处理“XML格式不正确”错误 常见XML well-formed问题解决方法  盐城做公司网站,江苏电子版退休证办理流程?  如何通过VPS建站无需域名直接访问?  Android滚轮选择时间控件使用详解 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。