类对象模型

95 阅读2分钟

「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战

💦 如何计算类对象的大小

#include<iostream>
using namespace std;
struct QueueNode
{
	QueueNode* next;
	int val;
};
class Queue
{
public:
	void Init();
	void Push(int x);
	void Pop();
private:
	QueueNode* head;
	QueueNode* tail;
};
int main()
{
	Queue q1;
	q1.Init();
	q1.Push(1);
	q1.Push(2);
	q1.Push(3);
	
	Queue q2;
	q2.Init();
	q2.Push(1);

	cout << sizeof(q1) << endl;
	cout << sizeof(q2) << endl;
	return 0;
}

❓ q1 和 q2 的大小 ❔

q1 和 q2 一样大,这里不要被它们 Push 了多少个数据所迷惑了,这些 Push 的数据都在堆上 malloc 空间存储,q1 和 q2 只是在栈上存储了指针指向堆里,所以不管 Push 了多少个数据,它的大小都是相同的

就像设计图和房子,一个房子住三个人,另一个房子住一个人,不会影响图纸的大小

注意类是不占内存空间的,它在编译前是放在文件里的,存在磁盘上。编译后,变成指令存在公共代码段;它定义的对象才会占用内存空间。算类型的大小就等同于算类型定义的对象的大小

Queue 里有三个函数二个变量,所以共计 20 Byte ❔

实际上不是,q1 和 q2 的大小在 32 位平台下是 8 Byte,好像是说对象里只存储了成员变量的大小

实际上在计算类型大小或者类对象时,只考虑成员变量,因为对象中只存了成员变量,没有存成员函数

💦 类对象的存储方式猜测

💨 方案一:对象中包含类的各个成员 在这里插入图片描述 缺陷:每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一个类创建多个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间。

💨 方案二:只保存成员变量,成员函数存放在公共的代码段 在这里插入图片描述

❓ 观察下面类的大小是多少 ❔

#include<iostream>
using namespace std;
class A
{
public:
	void Print()
	{}
private:
	int i;
	char ch;
};
//没有成员变量的类
class B
{
public:
	void Print()
	{}
};
//空类
class C
{};
int main()
{
	cout << sizeof(A) << endl;
	cout << sizeof(B) << endl;
	cout << sizeof(C) << endl;
	return 0;
}

📝 说明:

这里 A 占 8 个字节 (同结构体内存对齐)、B 占 1 个字节、C 占 1 个字节

没有成员变量的类/空类为啥是 1 个字节,难道不是 0 吗 ❓

我们说了实际上在计算类型大小或者类对象时,只考虑成员变量,那它没有成员变量,应该是 0。但是这个地方不能是 0, 注意计算类型的大小本质上是算这个类型定义变量的大小。如果一个类没有成员,那么它的对象需要给 1 Byte 进行占位来标识对象的存在 —— C c1,c2; (如果没有空间你怎么表示 c1、c2 存在) ,这 1 字节不存储有效数据

❓ 没有成员变量的类和空类有什么意义 ❔

目前看不到这样的场景,以后学到仿函数和 STL 的时候就能体现了。

💦 结构体内存对齐规则

【结构体相关面试题】

1、 结构体怎么对齐? 为什么要进行内存对齐?

2、如何让结构体按照指定的对齐参数进行对齐

3、什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景

结构体在 C 语言部分就学习了,这里就不细讲了,附上链接

《桃猿三结义:结构、枚举、联合》