IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 类对象所占用的空间 -> 正文阅读

[C++知识库]类对象所占用的空间

1.空类

类本身是没有大小的。类的大小指的是类的对象所占的大小。如果用 sizeof 运算符对一个类型名操作,得到的是具有该类型实体的大小。

#include<iostream>
using namespace std;

class A
{

};

int main()
{
	A obja;
	cout << sizeof(obja) << endl; // 1

	return 0;
}

C++标准指出,不允许一个对象的大小为 0,不同的对象不能具有相同的地址。这是由于:

  • new 需要分配不同的内存地址,不能分配内存大小为 0 的空间
  • 避免除以 sizeof(T) 时出现除以 0 的错误

因此,空类的 sizeof 为 1 的原因是为了让对象的实例能够相互区别。从上面代码可以看出,空类同样能够被实例化,所以编译器会给空类隐含地添加一个字节,这样空类实例化之后就会拥有独一无二的内存地址。

一旦空类中有其他的占用空间的成员,那么这 1 个字节就不计算在内,例如一个类只有一个 int 则占用 4 字节而不是 5 字节。

#include<iostream>
using namespace std;

class A
{
	int x;
};

int main()
{
	A obja;
	cout << sizeof(obja) << endl; // 4

	return 0;
}

2.一个类继承空类

当一个类继承空类时,空基类的一个字节并不会加到子类中去。

#include<iostream>
using namespace std;

class A
{

};

class B : public A
{

};

int main()
{
	A obja;
	cout << sizeof(obja) << endl; // 1

	B objb;
	cout << sizeof(objb) << endl; // 1

	return 0;
}
#include<iostream>
using namespace std;

class A
{

};

class B : public A
{
	int x;
};

int main()
{
	A obja;
	cout << sizeof(obja) << endl; // 1

	B objb;
	cout << sizeof(objb) << endl; // 4

	return 0;
}

3.空类作为另一个类的成员

当空类作为另一个类的成员时,空类的一个字节会计算在内。

然而,你会发现下面代码在大多数编译器中,B 的 sizeof 为 8。这是由于空类的大小虽然为 1,但是为了内存对齐,编译器会额外加上一些字节,使其被放大到足够可以存放一个 int。

#include<iostream>
using namespace std;

class A
{

};

class B
{
	int x;
	A a;
};

int main()
{
	A obja;
	cout << sizeof(obja) << endl; // 1

	B objb;
	cout << sizeof(objb) << endl; // 8

	return 0;
}

4.非静态成员变量

非静态的成员变量(即普通成员变量)跟着类对象走,是包含在每个对象中的,占用对象的内存空间,即每个类对象都有自己的成员变量。

#include<iostream>
using namespace std;

class A
{
public:
	int x;
};

int main()
{
	A obja;
	cout << sizeof(obja) << endl; // 4

	return 0;
}

5.静态成员变量

静态的成员变量不保存在对象内部,所占用的内存空间和类对象无关。

#include<iostream>
using namespace std;

class A
{
public:
	static int x;
	static int y;
};

int A::x = 0;
int A::y = 0;

int main()
{
	A obja;
	cout << sizeof(obja) << endl; // 1

	return 0;
}

6.非静态成员函数和静态成员函数

不论是静态的成员函数,还是非静态的成员函数,虽然写在类的定义中,但是不占用类对象的内存空间。不管有几个成员函数,都不影响对象的 sizeof。

#include<iostream>
using namespace std;

class A
{
public:
	void fun1() {};
	void fun2() {};
	void fun3() {};
	static void sfun() {};
};

int main()
{
	A obja;
	cout << sizeof(obja) << endl; // 1

	return 0;
}

7.构造函数和析构函数

构造函数和析构函数不影响类对象的 sizeof。

#include<iostream>
using namespace std;

class A
{
public:
	A() {};
	~A() {};
};

int main()
{
	A obja;
	cout << sizeof(obja) << endl; // 1

	return 0;
}

8.虚函数

首先需要明确一点,不管什么类型的指针 char *pint *p 占用的内存大小是固定的,在 x86 中是 4 字节,在 x64 中是 8 字节。

#include<iostream>
using namespace std;

int main()
{
	cout << sizeof(char*) << endl; // x86输出4,x64输出8
	cout << sizeof(int*) << endl; // x86输出4,x64输出8
	
	return 0;
}

类中有一个虚函数,那么这个类就会产生一个指向虚函数的指针;类中有两个虚函数,那么这个类就会产生两个指向虚函数的指针。

类本身指向虚函数的一个或一堆指针存放在一个表格里,这个表格被称为虚函数表(vtbl)。这个虚函数表一般是保存在可执行文件中的,在程序执行的时候载入到内存中来。虚函数表是基于类的,跟着类走的,和对象没有关系。

因为虚函数的存在,系统会往类对象中添加一个指针,这个指针正好指向这个虚函数表,这个指针被称为虚函数表指针(vptr)。vptr 的值由系统在适当的时机赋值,比如在构造函数中通过增加额外的代码来赋值。

因此,虚函数本身不计算在类对象的 sizeof 内,但是虚函数会让类对象的 sizeof 增加 4 个字节(x86)以容纳虚函数表指针。注意,不管有几个虚函数,类对象的 sizeof 都只增加 4 个字节(x86)。

#include<iostream>
using namespace std;

class A
{
public:
	virtual void fun1() {};
	virtual void fun2() {};
	virtual void fun3() {};
	virtual void fun4() {};
};

int main()
{
	A obja;
	cout << sizeof(obja) << endl; // x86输出4,x64输出8

	return 0;
}

9.总结

影响类对象大小的因素:

  • 普通成员变量
  • 虚函数:因为虚函数会让类对象的 sizeof 增加 4 个字节(x86)以容纳虚函数表指针。
  • 继承(单一继承,多重继承,重复继承,虚继承)
  • 字节对齐:如果有多个数据成员,那么为了提高访问速度,某些编译器可能会将数据成员之间的内存占用比例进行调整。

不影响类对象大小的因素:

  • 静态成员变量
  • 静态成员函数
  • 普通成员函数

分析下面代码中类对象的大小:

#include<iostream>
using namespace std;

class myobject
{
public:
	myobject() {};
	
	virtual ~myobject() {};

	float getvalue() const
	{
		return m_value;
	}

	static int s_getcount()
	{
		return ms_scount;
	}

	virtual void vfrandfunc() {};

protected:
	float m_value;
	static int ms_scount;
};

int myobject::ms_scount = 0;

int main()
{
	myobject obj;
	cout << sizeof(obj) << endl; // x86输出8:成员变量m_value占4字节、虚函数表指针占4字节

	return 0;
}

在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 15:59:31  更:2022-04-06 16:02:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:40:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码