5.C++面向对象2(类对象大小计算,结构体内存对齐,大小端存储方式,this指针)

news2024/9/21 22:04:46

⭐本篇文章为C++学习第4章,主要了解类对象大小和this指针

⭐本人C++代码仓库:yzc的c++学习: 小川c++的学习记录 - Gitee.com   

目录

一. 类对象模型

1.1 类成员函数和成员变量的分布

1.2 如何计算类的大小?(结构体内存对齐)

二. this指针

2.1 了解this指针

2.2 this指针特性 

三. 类和this指针相关面试题

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

3.2 如何让结构体按照指定的对齐参数进行对齐?能否按照3、4、5即任意字节对齐?

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

3.4 this指针存在地址空间哪里?

3.5 this指针可以为空吗?


一. 类对象模型

1.1 类成员函数和成员变量的分布

类中既有成员变量,又有成员函数,一个类实体包含了哪些内容??

可以通过获取不同类型的类大小进行分析

#include<iostream>
using namespace std;

//1.既有成员变量,也有成员函数
class A
{
	int a;
	int b;

	void f1()
	{}

	void f2()
	{}
};

//2.只有成员变量
class B
{
	int a;
	int b;
};

//3.只有成员函数
class C
{
	void f1()
	{}

	void f2()
	{}
};

//4.什么都没有
class D
{};


int main()
{
	cout << "A:" << sizeof(A) << endl;
	cout << "B:" << sizeof(B) << endl;
	cout << "C:" << sizeof(C) << endl;
	cout << "D:" << sizeof(D) << endl;
	return 0;
}

运行结果如下:

可以看到:

1. 拥有成员变量的A和B大小是8,而没有成员变量的C和D是1

2.拥有成员函数的C和没有成员函数的D都是1

所以:类只保存成员变量,将成员函数放在公共代码段。由于每一个类实体都有类成员函数,而成员函数在每一个类实体的作用是一样的,如果给每一个类实体都分配内存存储成员函数,就会占用大量过多的内存空间

注意:空类和只有成员函数类的大小是1,因为编译器要给一个标识符来标识这个类

1.2 如何计算类的大小?(结构体内存对齐)

使用sizeof可以轻松计算出一个类的大小,它是如何计算的??

需要使用结构体内存对齐规则:

1. 第一个成员变量在结构体偏移量为0的地址处

2. 其他成员变量对齐到某个数字(对齐数)的整数倍地址处

对齐数=min(编译器系统默认对齐数,该成员大小),VS默认对齐数是8各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数

3. 结构体大小为:最大对齐数的整数倍,最大对齐数为所有变量类型的最大者与默认对齐数的较小值

4. 如果嵌套了结构体,嵌套的结构体对齐到自己最大对齐数的整数倍,这个数也能成为对齐数(要和默认对齐数比较)

如:

#include<iostream>
using namespace std;

class A
{
	int a;	//偏移量为 0~4
	int b;	//偏移量为 4~8
	char c;	//偏移量为 8~9
};

int main()
{
	//总偏移量是9,最大对齐数=min(max(1,4),8)=4
	//结构体的大小为最大对齐数的整数倍,4 8 都小于9,所以大小为12
	cout << sizeof(A);
	return 0;
}

变量分布图如下:

运行结果:

如:

#include<iostream>
using namespace std;

//1.既有成员变量,也有成员函数
class A
{
	char arr[12];	// 0~12
	double b;		//大小为8,只能从8,16,24开始分配	16~24
	int c;			// 24~28
};


int main()
{
	//总偏移量是28,最大对齐数=min(max(1,8,4),8)=8
	//结构体的大小为最大对齐数的整数倍,为 4*8=32
	cout << sizeof(A);
	return 0;
}

变量分布图如下:

 

在c/c++中可以修改默认的对齐数

#pragma (4)    //将默认对齐数修改为4

二. this指针

2.1 了解this指针

为了方便了解this类,我们先创建一个日期类:

	d1.Set(2024, 9, 21);
	//本质
	this=&d1
	d1.Set(this, 2024, 9, 21);
	Set函数内部
	this->_year = year;
	this->_month = month;
	this->_day = day;

我们创建了d1实体,并且调用Set函数,问题是Set函数中没有传入d1的地址,Set函数是如何找到d1对象的呢?

实际上,Set函数包含了隐藏的this指针,当有一个实体调用这个函数的时候,就会把这个对象传递给this,再通过指针找到相应的变量

	d1.Set(2024, 9, 21);
	//本质
	this=&d1
	d1.Set(this, 2024, 9, 21);
	Set函数内部
	this->_year = year;
	this->_month = month;
	this->_day = day;

2.2 this指针特性 

1. this被const修饰,在成员函数中,无法给this赋值

2. 只能在成员函数内部使用

3. this指针本质是成员函数的形式参数,当对象调用成员函数的时候,将对象地址的实参传递给this形参,所以对象中不存储this指针

4. this指针是”成员函数“的第一个隐含的指针参数,一般由编译器通过ecx寄存器进行自动传递,不需要用户传递,使用方便

三. 类和this指针相关面试题

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

对齐方式:见本章1.2

为什么要进行内存对齐:

        1. 可以提高CPU读取数据的效率,如果不进行内存对齐,CPU需要执行更多的指令获取完整数据

        2. 硬件要求:有些处理器要求特定数据在特定地址上对齐,否则会导致错误

3.2 如何让结构体按照指定的对齐参数进行对齐?能否按照3、4、5即任意字节对齐?

使用 #pragma(指定对齐数),即可将默认对齐数改为指定对齐数

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

大小端是数据在内存存储方式。

大端:将数据的高位放在地址的低地址处,将数据的低位放在地址的高地址处。       

小端:将数据的低位放在地址的低地址处,将数据的高位放在地址的高地址处。

如:0x12345678

小端存储:

大端存储:

使用高位截断法判断机器存储方式

#include<iostream>
using namespace std;
//0x1234
//低地址-------------->高地址
//小端:12 34
//大端:34 12

int main()
{
	int a = 0x1234;		//整形占用4个字节,12是数据高位,34是数据低位
	char b = (char)a;	//字符型占用两个字节,强制转化会把高位截断
	if (b == 0x12)
	{
		//截断了34,说明34放在地址高位,数据低位放在高地址处,为大端存储
		cout << "小端存储!" << endl;
	}

	if (b == 0x34)
	{
		//截断了12,说明12放在地址高位,数据高位放在高地址处,为小端存储
		cout << "小端存储" << endl;
	}
	return 0;
}

运行结果:

3.4 this指针存在地址空间哪里?

this指针存在栈中,因为它是一个形式参数,函数参数都存在内存区域的栈中(linux)

在vs下,使用exc这个寄存器来传递,由于this指针需要经常用,寄存器速度较快

3.5 this指针可以为空吗?

this指针可以为空,这个时候在成员函数内部不能调用任何成员变量

#include<iostream>
using namespace std;

class A
{
public:
	void f1()
	{
		cout << "?????" << endl;
	}

	void f2()
	{
		cout << _a << endl;
	}

private:
	int _a = 123;
};


int main()
{
	A* p = nullptr;
	p->f1();//正常运行
	return 0;
}

运行结果:

如果使用 p 去调用f2函数就会崩溃

调试结果,由于this是nullptr,造成崩溃

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2153420.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

卸载node,安装nvm的详细使用方法

一、nvm是什么&#xff1f; nvm是一个node的版本管理工具&#xff0c;可以简单切换的node版本、安装、查看。。。等等&#xff0c;与npm不同的是&#xff0c;npm是依赖包的管理工具。 二、nvm下载安装 安装之前需要先把 自己电脑上边的node给卸载了&#xff0c;不然安装不好…

【数据结构初阶】链式二叉树接口实现超详解

文章目录 1. 节点定义2. 前中后序遍历2. 1 遍历规则2. 2 遍历实现2. 3 结点个数2. 3. 1 二叉树节点个数2. 3. 2 二叉树叶子节点个数2. 3. 3 二叉树第k层节点个数 2. 4 二叉树查找值为x的节点2. 5 二叉树层序遍历2. 6 判断二叉树是否是完全二叉树 3. 二叉树性质 1. 节点定义 用…

日志系统第三弹:日志消息和格式化模块的实现

日志系统第三弹&#xff1a;日志消息和格式化模块的实现 一、日志消息模块的实现二、日志格式化模块的设计1.格式化占位符的约定2.如何打印1.各种零件类1.抽象类2.简单的零件类3.日期零件类4.非格式化数据零件类 2.Formatter 3.如何解析 三、日志格式化模块的实现1.解析函数2.c…

一文详解Unity下RTMP推送|轻量级RTSP服务|RTSP|RTMP播放模块说明

技术背景 好多开发者&#xff0c;对Unity下的模块&#xff0c;不甚了解&#xff0c;实际上&#xff0c;除了Windows/Linux/Android/iOS Native SDK&#xff0c;大牛直播SDK发布了Unity环境下的RTMP推流|轻量级RTSP服务&#xff08;Windows平台Linux平台Android平台&#xff09…

Windows安装Oracle11gR2(图文教程)

本章教程&#xff0c;记录在Windows10上安装Oracle11gR2过程。 一、下载安装包 通过网盘分享的文件&#xff1a;oracle11g 链接: https://pan.baidu.com/s/15ilciQ5NlKWtClklmdAH_w?pwds4dd 提取码: s4dd 二、下载并解压文件 将网盘中的安装包文件下载到本地&#xff0c;在此之…

谷歌收录查询工具,好用的谷歌收录查询工具应具备的这5个特性

在探讨如何高效利用谷歌收录查询工具以优化网站可见性和搜索引擎排名时&#xff0c;好用这一标准往往涵盖了工具的准确性、易用性、功能全面性以及对搜索引擎算法变化的适应性等多个方面。 1.准确性 首先&#xff0c;一款好用的谷歌收录查询工具必须能够提供高度准确的数…

C Prime Plus 第6章习题

你该逆袭了 红色标注的是&#xff1a;错误的答案 蓝色标注的是&#xff1a;正确的答案 绿色标注的是&#xff1a;做题时有疑问的地方 橙色标注的是&#xff1a;答案中需要着重注意的地方 练习题 一、复习题1、2、3、4、5、我的答案&#xff1a;错误正确答案&#xff1a; 6、7、…

窥探 引用拷贝、浅拷贝、深拷贝 的那些事 (clone版)

谁家玉笛暗飞声 散入春风满洛城 往期回顾✨内部类 目录✨ 引用拷贝 介绍 总结 浅拷贝 介绍 浅拷贝的步骤 深拷贝 介绍 引用拷贝 介绍 引用拷贝就是我们常用的 “赋值” &#xff0c;只是复制了原对象的引用&#xff0c;即两个对象指向同一块内存堆地址。修改其中的一个对象会影…

【图灵完备 Turing Complete】游戏经验攻略分享 Part.6 处理器架构2 函数

新的架构来了&#xff0c;本游戏的最后一个攻略分享&#xff0c;最后汇编部分无非是对于操作码的熟练&#xff0c;硬件没有问题&#xff0c;那么也就无关痛痒了。 汇编实现&#xff0c;两数相或和两数相与非一起相与即可。 八位异或器&#xff0c;整就完事了。 有手就行。 利…

【梯度下降算法学习笔记】

梯度下降单参数求解 经过之前的学习我们来引入梯度下降的理念 α \alpha α为学习率 w 1 w 初 − α ∂ J ( w ) ∂ w w_1w_初-\alpha\frac{\partial J(w)}{\partial w} w1​w初​−α∂w∂J(w)​ w 2 w 1 − α ∂ J ( w 1 ) ∂ w 1 w_2w_1-\alpha\frac{\partial J(w_1)}…

国庆电影扎堆来袭,AI智能体帮你推荐必看佳片!(附制作教程)

大家好&#xff0c;我是凡人。 今天看到新闻&#xff0c;发现国庆有10部影片要扎堆儿上映&#xff0c;对于选择困难症的我属实有点难选&#xff0c;同时也想避开一些坑省的浪费金钱和时间。 本着不知道就问AI的习惯&#xff0c;想问问大模型怎么看&#xff0c;但做了简单的交…

MySQL 优化器:理解与探秘

在 MySQL 数据库的世界里&#xff0c;优化器扮演着至关重要的角色。它就像是一位幕后的魔法师&#xff0c;默默地为数据库的高效运行贡献着力量。那么&#xff0c;MySQL 优化器究竟是什么&#xff1f;它又是如何工作的呢&#xff1f;让我们一起来揭开它的神秘面纱。 一、MySQL…

行业人工智能研究-Python自监督方式学习图像表示算法

学术界人工智能研究落后于工业界 摘要 行业或工业界在人工智能研究上超出学术界&#xff0c;并占据着大量的计算力&#xff0c;数据集和人才诱人的薪水和明朗的预期吸引大量人才离开学术界&#xff0c;涌入行业或工业界即使&#xff0c;比如Meta开源其人工智能模型&#xff0…

二分查找算法(1) _二分查找_模板

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 二分查找算法(1) _二分查找模板 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 1. 二…

掌握Android开发新趋势:Jetpack与现代架构技术全解析

随着Android开发技术的不断进步&#xff0c;Jetpack和现代架构技术已成为构建高效、可维护应用的关键。本文将为您介绍一套全面的学习资料&#xff0c;包括大纲、PDF文档、源代码以及学习视频&#xff0c;帮助您深入理解Jetpack核心库、架构组件以及现代开发工具。 内容&#…

linux-基础知识4

网络连接性测试 ping ping可以用来测试本机与目标主机的连通速度网络稳定性 ping -c 5 -s 1024 目标主机ip地址 -c 表示ping包的个数,linux如果缺省-c会一直ping下去&#xff0c;windows平台的选项是-n -s指定ping发送数据的字节数默认是84字节。windows的是-l 没有问题时会之…

如何设计出一个比较全面的测试用例

目录 1. 测试用例的基本要素(不需要执行结果) 2. 测试用例的给我们带来的好处 3. 用例编写步骤 4. 设计测试用例的方法 4.1 基于需求进行测试用例的设计 4.2 具体的设计方法 1.等价类 2.边界值 3.判定表&#xff08;因果图&#xff09; 4.正交表法 5.场景设计法 6.错误猜测…

IO流体系(FiletOutputStream)

书写步骤&#xff1a; 1.创建字节输出流对象 细节1:参数是字符串表示的路径或者是File对象都是可以的 细节2:如果文件不存在会创建一个新的文件&#xff0c;但是要保证父级路径是存在的。 细节3:如果文件已经存在&#xff0c;则会清空文件 2.写数据 细节:write方法的参数…

Python | 绘制核密度图

写在前面 台风天&#xff0c;适合敲代码。前两天正好看到一个有意思的核密度图&#xff0c;使用的是seaborn绘制的。之前了解过这个包&#xff0c;但是一致没有去绘制相关的图&#xff0c;这次正好去学习一下相关的函数。 绘制结果如下所示&#xff1a; 主要两个有意思的地方…

二维光场分析

一、单色光波长的复振幅表示 实波函数 复波函数 复振幅 由于时间因子相同,可以用复振幅来描述 光强 1.1 球面波的复振幅(单色点光源发出的光波) 等相位面是同心球面,波矢处处与等相位面垂直,即 是 r = 1 处的振幅 发散球面波: 会聚球面波: <