C++类的大小——sizeof(class)
第一:空类的大小
class CBase
{
};
运行cout<<"sizeof(CBase)="<<sizeof(CBase)<<endl;
输出
sizeof(CBase)=1;
为什么空的什么都没有是1呢?
先了解一个概念:类的实例化,所谓类的实例化就是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。同样空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。
第二:一般非空类大小
class CBase
{
int a;
char *p;
};
运行结果:
sizeof(CBase)=8
第三:有虚函数类
class CBase
{
public:
CBase(void);
virtual ~CBase(void);
private:
int a;
char *p;
};
运行结果:
sizeof(CBase)=12
“C++ 类中有虚函数的时候有一个指向虚函数的指针(vptr),在32位系统分配指针大小为4字节”。
第四:有虚函数类的继承
基类就是上面的了不写了
class CChild :
public CBase
{
public:
CChild(void);
~CChild(void);
private:
int b;
};
运行结果:
sizeof(CChild)=16;
可见子类的大小是本身成员变量的大小加上父类的大小。
另外:
1. 空类
class A
{
};
void main()
{
printf("sizeof(A): %d\n", sizeof(A));
getchar();
}
得到结果为:1。
类的实例化就是给每个实例在内存中分配一块地址。空类被实例化时,会由编译器隐含的添加一个字节。所以空类的size为1。
2.虚函数
class A
{
virtual void FuncA();
virtual void FuncB();
};
得到结果:4
当C++ 类中有虚函数的时候,会有一个指向虚函数表的指针(vptr),在32位系统分配指针大小为4字节。所以size为4.
3.静态数据成员
class A
{
int a;
static int b;
virtual void FuncA();
};
得到结果:8
静态数据成员被编译器放在程序的一个global data members中,它是类的一个数据成员.但是它不影响类的大小,不管这个类实际产生了多少实例,还是派生了多少新的类,静态成员数据在类中永远只有一个实体存在。
而类的非静态数据成员只有被实例化的时候,他们才存在.但是类的静态数据成员一旦被声明,无论类是否被实例化,它都已存在.可以这么说,类的静态数据成员是一种特殊的全局变量.
所以该类的size为:int a型4字节加上虚函数表指针4字节,等于8字节。
4.普通成员函数
class A
{
void FuncA();
}
结果:1
类的大小与它的构造函数、析构函数和其他成员函数无关,只已它的数据成员有关。
5.普通继承
class A
{
int a;
};
class B
{
int b;
};
class C : public A, public B
{
int c;
};
结果为:sizeof(C) =12.
可见普通的继承,就是基类的大小,加上派生类自身成员的大小。
6.虚拟继承
class C : virtual public A, virtual public B
{
int c;
};
结果:16.
当存在虚拟继承时,派生类中会有一个指向虚基类表的指针。所以其大小应为普通继承的大小(12字节),再加上虚基类表的指针大小(4个字节),共16字节。
类的大小问题实验剖析:
1、空类:
C++编译器强制给这种类插入一个缺省成员,长度为1。如果有自定义的变量,变量将取代这个缺省成员。
class A
{};
cout<<sizeof(A); //输出1
2、只有一个char型
class A
{
char c;
};
cout<<sizeof(A); //输出1
3、有5个char型
class A
{
char a,b,c,d,e;
};
cout<<sizeof(A); //输出5
4、一个char型 + 一个int型:字节对齐
class A
{
char c;
int a;
};
cout<<sizeof(A); //输出8
5、2个char型 + 一个int型
class A
{
char c,d;
int a;
};
cout<<sizeof(A); //输出8
6、5个char型 + 一个int型
class A
{
char c,d,e,f,g;
int a;
};
cout<<sizeof(A); //输出12
7、1个char型 + 1个int型 + 2个char型
class A
{
char c;
int a;
char d,e;
};
cout<<sizeof(A); //输出12
8、普通函数不占空间
class A
{
void B(){ int d; }//0Byte
int C(){};
};
cout<<sizeof(A); //输出1,等同于空类
9、虚函数 占4个字节:指向虚函数表的指针
class A
{
virtual void C(){}
};
cout<<sizeof(A); //输出4
10、多个虚函数等同于1个虚函数
class A
{
virtual void C(){}
virtual void D(){}
};
cout<<sizeof(A); //输出4
11、多继承问题中sizeof
class b{};
class c :public b
{
virtual void fun() = 0;
};
class d :public b ,public c{};
cout<<sizeof(d); //输出8,字节对齐(b+c)
12、单继承问题中sizeof
class b{};
class c :public b
{
virtual void fun() = 0;
};
class d :public c{};
cout<<sizeof(c); //输出4
cout<<sizeof(d); //输出4
13、静态数据成员 和 成员函数 不占空间
class A
{
static int a;
static int b(){};
};
cout<<sizeof(A); //输出1
14、const数据变量占空间 和 const成员函数不占空间
class A
{
public:
const int b;
const int c;
virtual void f(){}
int d() const{}
int e() const{}
virtual void g(){}
A() :b(2), c(3)
{
}
};
cout<<sizeof(A); //输出12= 4+4+4(多个虚函数算一个)
空类的大小
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;
}
结果自然是
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;
};
这个时候,结果就变成了
12
24
一个char c;增加了4字节,说明类的大小也遵守类似class字节对齐,的补齐规则。
至此,我们可以归纳以下几个原则:
1.类的大小为类的非静态成员数据的类型大小之和,也就是说静态成员数据不作考虑。
2.普通成员函数与sizeof无关。
3.虚函数由于要维护在虚函数表,所以要占据一个指针大小,也就是4字节。
4.类的总大小也遵守类似class字节对齐的,调整规则。
5、不占空间的有:普通函数,静态数据成员,静态成员函数。
6、无论多少个,只相当于一个所占的空间:虚函数。
7、空类占1个字节。
8、既有字符型又有整型,要考虑字节对齐。
9、普通数据成员、const数据成员占空间;静态成员不占空间。
参考:
https://blog.csdn.net/u010069101/article/details/51045840
https://blog.csdn.net/hairetz/article/details/4171769
https://blog.csdn.net/zzhongcy/article/details/38361755
C++类的大小——sizeof(class)的更多相关文章
- 类的大小——sizeof 的研究
类的大小——sizeof 的研究(1) 先看一个空的类占多少空间? class Base { public: Base(); ~Base(); }; 注意到我这里显示声明了构造跟析构,但是sizeof ...
- sizeof求类的大小
用sizeof求类的大小,http://blog.csdn.net/szchtx/article/details/10254007(sizeof浅析(三)——求类的大小),这篇博文给出了非常详尽的举例 ...
- c++空类的大小
初学者在学习面向对象的程序设计语言时,或多或少的都些疑问,我们写的代码与最终生编译成的代码却大相径庭,我们并不知道编译器在后台做了什么工作.这些都是由于我们仅停留在语言层的原因,所谓语言层就是教会我们 ...
- C++空类以及没有成员变量的类的大小
关于C++中空类的大小为1,我们大家都有所了解,但是除了空类之外的其他一些没有成员变量的类的大小,还是有很多不明之处的. 我们来看如下一个例子: #include<iostream> us ...
- C++类的大小
C++类的大小 一个空类class A{};的大小为什么是1,因为如果不是1,当定义这个类的对象数组时候A objects[5]; objects[0]和objects[1]就在同一个地址处,就无 ...
- 关于虚拟继承类的大小问题探索,VC++ 和 G++ 结果是有区别的
昨天笔试遇到个 关于类占用的空间大小的问题,以前没怎么重视,回来做个试验,还真发现了问题,以后各位笔试考官门,出题时请注明是用什么编译器. vc6/vc8 cl 和 Dev-C 的g++ 来做的测试: ...
- C++类对象大小的计算
(一)常规类大小计算 C++类对象计算需要考虑很多东西,如成员变量大小,内存对齐,是否有虚函数,是否有虚继承等.接下来,我将对此举例说明. 以下内存测试环境为Win7+VS2012,操作系统为32位 ...
- C++类的大小计算汇总
C++中类涉及到虚函数成员.静态成员.虚继承.多继承.空类等. 类,作为一种类型定义,是没有大小可言的. 类的大小,指的是类的对象所占的大小.因此,用sizeof对一个类型名操作,得到的是具有该类型实 ...
- C++学习笔记(8)----C++类的大小
C++类的大小 (i) 如下代码: #include<iostream> using namespace std; class CBase { }; class CDerive :publ ...
随机推荐
- Spring boot 问题总结
1. Spring boot 嵌入的tomcat不能启动: Unregistering JMX-exposed beans on shutdown 在官网(http://start.spring. ...
- EasyUi通过OCUpload上传及POI上传 实现导入xls表格功能
Easyui上传文件案例 第一步:要想使用OCUpload首先前端需要导入js包 <script type="text/javascript" src=&qu ...
- TensorFlow 1.2.0新版本完美支持Python3.6,windows在cmd中输入pip install tensorflow就能下载应用最新tensorflow
TensorFlow 1.2.0新版本完美支持Python3.6,windows在cmd中输入pip install tensorflow就能下载应用最新tensorflow 只需在cmd中输入pip ...
- 102.自己实现ArrayList
package collection; import java.util.ArrayList; import java.util.List; /** * 自己实现一个ArrayList,帮助理解底层结 ...
- [转载]图解程序员必须掌握的Java常用8大排序算法
这篇文章主要介绍了Java如何实现八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序,分享给大家一起学习. 分类1)插入排序(直接插入排序.希尔排 ...
- How to use Nissan consult 3 plus to check, make key and program?
How to use Nissan consult 3 plus to test Nissan? Firstly: get one particular Nissan consult 3 plus. ...
- QXDM操作应用
QXDM(The QUALCOMM Extensible Diagnostic Monitor)是高通公司(Qualcomm)公司发布的可以对手机终端所发数据进行跟踪有效工具,通过对数据的分析可以诊断 ...
- Powerpoint 演示时定时提醒工具
经常碰到这样的场景,规定的演讲报告时间所剩无几,甚至是已经超时,但演讲者并不知情,做为主持人只能从旁边轻轻的善意的提醒,但有时演讲者会没注意到主持人的提醒... 这里要介绍的就是这样一款用于提醒演讲者 ...
- 将GPS获得的UTC时间转换成本地时间的方法(转)
源: 将GPS获得的UTC时间转换成本地时间的方法 参考: gps时转换为utc时间方法
- amoeba_mysql 读写分离
环境 amoeba需要java环境,配置:略. MySQL主从配置:略. 基本架构 MySQL主:192.168.31.140 MySQL从:192.168.31.150 MySQL代理:192.16 ...