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类中有多个虚函数,只算一次))。

如上,就是我对于这种类型的总结,这种问题只能出现一次!!!

加油,放平心态。念念不忘,必有回响!!!

时间: 2024-10-07 17:43:01

C++类的实例化对象的大小之sizeof()的相关文章

c++中实例化对象的大小(转)

今天随手写了一个类,用sizeof()测试实例化类对象的大小时遇到了一些问题. 一般来说,对象大小由数据成员大小决定,不包含成员函数的大小. 在网上找了一篇很详细的例子,我遇到的问题为实例三情形,涉及到编译器的优化. 之所以写这篇<C++类的实例化对象的大小之sizeof()>,是因为在参加笔试的时候遇到如下这么一道题,当时感觉就是这个一个坑,但,我还是义无反顾的跳了下去,因为存在知识点盲区啊.现,总结一下,你不知道的C++类的实例化对象的大小之sizeof(). class D{public

面向对象-类与实例化对象

类: 一系列对象相似特征与技能的结合体 注:站在不同角度,分类不一样 在现实世界中:一定先有对象,再有类 在程序中:一定需先有类,再有对象 定义类并实例化对象: #定义类 class LuffyStudent: school='luffycity' def learn(self): print('is learning') def eat(self): print('is eating') def sleep(self): print('is sleeping') #实例化对象 stu1=Luf

波哥学JAVA,定义类 创建对象 实例化对象 属性 类调用属性或者方法

定义类 声明对象  创建对象 实例化对象 属性 对象调用属性或者方法 举例,下面定义类了一个类并声明属性,写了一个方法: 创建对象 实例化对象 属性 类调用属性或者方法

java反射1--产生Class类的实例化对象三个方法

首先每一个类在实例化的时候都会产生一个.class文件.而Class对象既是将.class文件读入内存时,为它创建一个Class对象. 反射就是对Class对象进行操作. 1 package reflect.vo; 2 3 /** 4 * @author guohao 5 * java测试类Student 6 */ 7 public class Student { 8 private String name; 9 private int age; 10 private float score;

动态加载类并实例化对象 —— newInstance

一.Class.forName("").newInstance(); 1. Class.forName( )静态方法的目的是为了动态加载类(初始化类).在加载完成后,一般还要调用Class下的newInstance( )静态方法来实例化对象以便操作.因此,单单使用Class.forName( )是动态加载类是没有用的,其最终目的是为了实例化对象. 2. newInstance: 弱类型.低效率.只能调用无参构造. new: 强类型.相对高效.能调用任何public构造. 二.Class

java反射-反射实例化对象-反射获得构造方法-反射获得普通方法-获得属性

链接:https://www.zhihu.com/question/24304289/answer/38218810来源:知乎著作权归作者所有,转载请联系作者获得授权. Class<?> cls = Class.forName("cn.mldn.demo.Person"); // 取得Class对象 第一步:获得对象,构造方法,普通方法,属性 Object obj = cls.newInstance() Constructor<?> cons = cls.get

类定义和对象创建

类和对象介绍 类即类别.种类,是面向对象设计最重要的概念, 对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体 在现实世界中:先有对象,再有类,对象是具体的存在,而类仅仅只是一个概念,并不真实存在 #在程序中,务必保证:先定义类,后使用类产生对象 PS: 1. 在程序中特征用变量标识,技能用函数标识 2. 因而类中最常见的无非是:变量和函数的定义 定义类 class 类的名称: # 类中的内容 描述属性和技能 #描述属性用变量 #描述行为用函数 #类名称 书写规范 首先是见名知

类实例 及 实例化对象 对象引用

类实例及成员引用 当我们创建完一个类,如果要使用这个类,必须在程序里创建类的实例对象,通过这个实例来引用类中所定义的方法成员,完成所需的工作.创建实例对象时,必须使用new关键字,这个关键字我们在集合和哈希表对象的创建时用到过,基本方法一致,就是用new关键字产生一个指向类实例对象所在位置的引用.实例化类对象的基本语法为: ClassName ObjName=new ClassName([参数]): 类的名字       对象名                           是否有参数.多

PHP面相对象:声明类和实例化类

一.类的声明 1 //使用class关键词+类名+{}声明一个类 2 class Demo { //类名首字母需要大写,命名遵守驼峰命名法 3 var $name; //[修饰词] 变量名 4 5 function test(){ 6 echo "helloworld"; 7 } 8 } 9 10 //实例化对象,使用new关键词 11 $t1 = new Demo; 12 13 //对象的访问 14 $p1->test(); 二.类在内存中的分配 数据段 通常是指用来存放程序中