C++类的实例化对象的大小之sizeof()
之所以写这篇《C++类的实例化对象的大小之sizeof()》。是由于在參加笔试的时候遇到例如以下这么一道题,当时感觉就是这个一个坑,但。我还是义无反顾的跳了下去,由于存在知识点盲区啊。现,总结一下。你不知道的C++类的实例化对象的大小之sizeof()。
class D
{
public:
D()
{ } virtual ~D()
{ } private:
int a ;
char *p;
};
实例一:
class A
{
}; A a;
cout << sizeof(a) << endl;
执行结果:1
解释:空类,没有不论什么成员变量或函数。即没有不论什么存储内容;可是由A a可知,空类仍然可以实例化。一个类可以实例化,编译器就需给它分配内存空间,来指示类实例的地址。这里编译器默认分配了一个字节,以便标记可能初始化的类实例。同一时候使空类占用的空间最少(即1字节)。
实例二:
class B
{
private:
int a;
};
B b;
cout << sizeof(b) << endl;
执行结果:4
解释:当类中有其他成员占领空间时,那一个字节就不算在内了,如本题:结果是4,而不是1+4=5。
实例三:
class BB
{
private:
int a ;
char b;
};
BB bb;
cout << sizeof(bb) << endl;
执行结果:8
解释:什么?怎么会是8?不应该是4 + 1 = 5吗?这里考察了对齐,涉及到编译器的优化。
对于大多数CPU来说,CPU字长的整数倍操作起来更快,因此对于这些成员加起来不够这个整数倍,有可能编译器会插入多余的内容凑足这个整数倍。此外,有时候相邻的成员之间也有可能由于这个目的被插入空白,这个叫做“补齐”(padding)。所以,C++标准紧紧规定成员的排列依照类定义的顺序,可是不要求在存储器中是紧密排列的。因此,如上的一个字节的char在存储时被补全了,成为了4个字节。
实例四:
class C
{
private:
int a ;
char *p;
};
C c;
cout << sizeof(c) << endl;
执行结果:8
解释:普通情况下,假设是指针,则不管指针指向的是什么数据类型,都占4个字节的存储空间。
实例五:
class D
{
public:
D()
{ } virtual ~D()
{ } private:
int a ;
char *p;
};
D d;
cout << sizeof(d) << endl;
执行结果:12
解释:考察虚函数。当类含有虚函数时,(不论是自己的虚函数,还是继承来的),那么类中就有一个成员变量信息:虚函数指针(4个字节)。这个指针指向一个虚函数表,虚函数表的第一项是类的typeinfo信息,之后的项为此类的全部虚函数的地址。
更进一步的解释:当类中有虚函数的时候,编译器会为类插入一个我们看不及爱你的数据并建立一个表。这个表就是虚函数表。那个我们看不见的数据就是指向虚函数表的指针——虚表指针。虚函数表就是为了保存类中的虚函数的地址。
我们能够把虚函数表理解成一个数组,数组中的每一个元素存放的就是类中虚函数的地址。当调用虚函数的时候,程序不是像普通函数那样直接跳到函数的代码处,而是先取出虚表指针即得到虚函数表的地址,依据这个来到虚函数表里,从这个表理取出该函数的指针。最后调用该函数。
实例六:
class E
{
public:
E()
{ } virtual ~E()
{ } private:
int a ;
char *p;
static int b;
};
E e;
cout << sizeof(e) << endl;
执行结果:12
解释:考察静态成员变量的内存分配。
因为静态成员变量是在静态存储区分配空间的,它不属于实例的一部分。因此类中的static成员变量不占领空间。
实例七:
class F:public E
{
public:
F()
{ } ~F()
{ } private:
int c;
};
E e;
cout << sizeof(e) << endl;
执行结果:16
解释:派生类对象的存储空间 = 基类存储空间 + 派生类特有的非static数据成员的空间
实例八:
class G: public virtual E
{
public:
G()
{ } ~G()
{ } private:
int c;
};
G g;
cout << sizeof(g) << endl;
执行结果:20
解释:假设是虚继承的话,类对象的存储空间大小 = 基类的存储空间 + 派生类特有的非static数据成员的存储空间 + 每个类的虚函数存储空间(这个是额外加的。即依照这个公式。sizeof(g) = 12(E基类的存储空间) + 4(G特有的非static数据成员的存储空间) + 4(E类的虚函数的存储空间。假设E类中有多个虚函数,仅仅算一次))。
实例九:
class H: public virtual E
{
public:
H()
{ } ~H()
{ } virtual void GetValue()
{ } private:
int c;
};
H h;
cout << sizeof(h) << endl;
执行结果:24
解释:对照实例八,依照上面的解释:类对象的存储空间大小 = 基类的存储空间 + 派生类特有的非static数据成员的存储空间 + 每个类的虚函数存储空间(sizeof(h) = 12(E基类的存储空间) + 4(G特有的非static数据成员的存储空间) + 4(E类的虚函数的存储空间,假设E类中有多个虚函数,仅仅算一次)+ 4(H类的虚函数的存储空间,假设H类中有多个虚函数。仅仅算一次))。
如上,就是我对于这样的类型的总结,这样的问题仅仅能出现一次!
!
!
加油。放平心态。念念不忘,必有回响!
!!
C++类的实例化对象的大小之sizeof()的更多相关文章
- python的类和实例化对象
一切皆对象,类也是对象,类来自于元类type,如果一个类没有声明自己的元类,默认它就是元类. 即类是元类的实例,通过type(类)会显示type,而实例来自于类. 类有两个属性,数据属性和函数属性,下 ...
- python中如何统计一个类的实例化对象
类中的静态变量 需要通过类名.静态变量名 来修改 :通过对象不能修改 python中如何统计一个类的实例化对象?? class Person: #静态变量count,用于记录类被实例化的次数 coun ...
- 一个类的实例化对象所占空间的大小(对象大小= vptr(可能不止一个) + 所有非静态数据成员大小 + Aligin字节大小(依赖于不同的编译器))
注意不要说类的大小,是类的对象的大小. 首先,类的大小是什么?确切的说,类只是一个类型定义,它是没有大小可言的. 用sizeof运算符对一个类型名操作,得到的是具有该类型实体的大小. 如果 Class ...
- JavaSE复习日记 : 实例化对象/构造方法和this关键字
/* * 实例化对象/对象的构造方法/this关键字 */ /* * 实例化对象 * * 就是实例化某一个类; * 从不同角度去理解的话就是: * 1. 从人的认知角度: * 就是具体化某个东西; * ...
- 一篇文章看懂java反射机制(反射实例化对象-反射获得构造方法,获得普通方法,获得字段属性)
Class<?> cls = Class.forName("cn.mldn.demo.Person"); // 取得Class对象传入一个包名+类名的字符串就可以得到C ...
- C++一个类对象的大小计算
计算一个类对象的大小时的规律: 1.空类.单一继承的空类.多重继承的空类所占空间大小为:1(字节,下同): 2.一个类中,虚函数本身.成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空 ...
- 创建java类并实例化类对象
创建java类并实例化类对象例一1.面向对象的编程关注于类的设计2.设计类实际上就是设计类的成员3.基本的类的成员,属性(成员变量)&方法 面向对象思想的落地法则一:1.设计类,并设计类的成员 ...
- 如何导出标准模板库(STL)类的实例化和包含STL类对象数据成员的类
本文翻译自 https://support.microsoft.com/zh-cn/help/168958/how-to-export-an-instantiation-of-a-standard-t ...
- static 成员变量、static 成员函数、类/对象的大小
一.static 成员变量 对于特定类型的全体对象而言,有时候可能需要访问一个全局的变量.比如说统计某种类型对象已创建的数量. 如果我们用全局变量会破坏数据的封装,一般的用户代码都可以修改这个全局变量 ...
随机推荐
- Python学习笔记012——装饰器
1 装饰器 1.1装饰器定义 在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator). 1.2 装饰器分类 装饰器:函数装饰器,类装饰器,函数的装饰器,类的装饰器 装饰器:函数装饰函 ...
- 安装完SqlServer2008,wamp服务器无法启动的问题
"开始"->"程序"->Microsoft SQL Server 2008->配置工具->SQL Server配置管理器->SQL ...
- CSU1256 天朝的单行道(spfa)
1256: 天朝的单行道 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 281 Solved: 92 [Submit][Status][pid=12 ...
- C# POST与参数的字符串格式
参数拼接方法:& 类似url参数.然后转化为字节型 string postdate = "Submit=" + Submit + "&dopost=&q ...
- python标准库介绍——23 UserString 模块详解
==UserString 模块== (2.0 新增) ``UserString`` 模块包含两个类, //UserString// 和 //MutableString// . 前者是对标准字符串类型的 ...
- 高效使用 JavaScript 闭包,避免 Node.js 应用程序中的内存泄漏
在 Node.js 中,广泛采用不同形式的闭包来支持 Node 的异步和事件驱动编程模型.通过很好地理解闭包,您可以确保所开发应用程序的功能正确性.稳定性和可伸缩性. 闭包是一种将数据与处理数据的代码 ...
- 多主机共享ssh Public/Private Key
前期服务器比较少,所有代码都放在github的私库中,在自己的github 设置中设置SSH keys就可以拉下相应的库中的代码到本地与服务器了,但是最近服务器多家了几台,每台都生成key加到gith ...
- javascript跟随滚动效果插件代码(javascript Follow Plugin)
这篇文章介绍了javascript跟随滚动效果插件代码(javascript Follow Plugin),有需要的朋友可以参考一下Js 跟随滚动效果插件支持定义多个跟随ID,采用css fixed属 ...
- paip.索引的种类以及实现attilax 总结
paip.索引的种类以及实现attilax 总结 1. 索引的类型 1 2. Btree索引(分块索引) 1 3. Hash 索引(编号索引) 1 4. 倒排索引 2 5. 对大型文本文件做索引 2 ...
- [MySQL] MySQL中关于外键报错的解决和建议
一.缘由 今天在恢复从库和主库不同步的数据时,看到关于外键的报错. ERROR 1451 (23000): Connot delete or update a parent row: a foreig ...