C++基础之类二(类的实例化,This指针)

目录

类的实例化

概念

类和对象的区别

计算一个类

不同的类的大小

类的存储模型

内存对齐

让结构体按照指定的默认对齐数进行对齐

确定偏移量

大小端字节序

This指针

概念

this指针四大特性

一些关于this指针的问题

总结


之前学过了类,但在编程中类无法直接使用,需要将类进行实例化后才能使用,现在就来看看类的实例化是什么?

类的实例化

概念

用类创建对象的过程叫做类的实例化,类可以抽象为虚拟的图纸,对象是按照图纸创建好的类,创建的过程就是类的实例化。

类和对象的区别

对象是按照类创建的实体,所以对象的功能是按照类的设计,但两者之间还有很多不同点

对象
虚拟实体
不占用内存空间占用内存空间
不参与程序运行参与程序运行
不存在生命周期生命周期具体看所在是全局域还是局部域

计算一个类

不同的类的大小

有内容的类:

看一下下面的代码,它的大小应该是多少?

class Bit
{
public:int A(char x, int y){return (a + x) - (b + y);}
private:char a;int b;
};

看一下其中的元素,一个成员函数,两个成员变量,32位系统的情况下,成员函数的地址是4个字节,char类型是1字节,int类型是4字节,按照内存对齐的规则,这个类应该是12字节的大小,但实际的运算结果是8字节。

无内容的类:

再看一下下面的代码,它的大小又是多少?

class Bit
{};

什么都没有,那它的字节应该是0,但实际上它的字节数是1。

类的计算结果这么奇怪,中间起决定性因素的是类的存储模型 

类的存储模型

C++之父在创建类的模型是充分考虑了类被实例化的情况,所以设计了一个极为简单的存储模型,那就是将类中的成员函数放到常量区,而类中只保留成员变量。

下面的图表是一个类,在实例化后,对象中的成员函数被放到一个公共区域中,对象中只存放成员变量,所以计算对象的结果为8个字节,同时这个特性也被保留在了类中,所以sizeof(Bit)(注意这里计算的只是类,不是对象)得到的结果也是8个字节。

对于空类,空类没有内容,但考虑到类会实例化为多个对象,所以会分配给类1个字节作为占位符,占位符中部存储有效内容,仅仅表示类的存在。

类中的成员函数保存到常量区,不用担心找不到,是因为整个过程由编译器完成。

内存对齐

内存对齐的概念

现代计算机都是按照Byte作为划分单位的,从理论上讲,访问任何类型的变量都可以从任意的位置开始,但在实际操作的过程中,特殊类型的变量需要放在特殊的位置,这句需要特殊类型的变量按照一定的规则存放在内存中,而不是一个接一个的放在一起,这就是内存对齐。

为什么需要内存对齐

内存对齐主要有两个原因:

一是不同架构的cpu对数据存储及读取的方式不同,在某些CPU上任意位置读取可能会发生错误。

二是为了提升效率,假设一个32位系统下的int变量,它占据4个字节,一些平台读取是从偶地址开始读取,int变量放在偶地址开始时,只要一个读周期就能完成数据读取,但放在奇地址需要两个读周期,才能将数据读完,之后还要将数据高低字节拼凑才能得到完整的数据。

内存对齐的规则

内存对齐一共四点规则

一、特殊变量(这里指结构体,类,联合体等自定义变量)放入内存时,第一个数据存放在标记为offset为0的地址,之后的数据按照数据的大小或者数据的子数据(结构体中嵌套结构)的大小的整数倍。

以该类为例class  BIT
{char a;int b;}

 

在32位系统下,char类型变量a占据1个字节,a放在偏移量为0的位置,int类型变量b占据4个字节,按照规则将放在数据的整数倍的位置,所以放在偏移量为4的位置。

二、自定义类型变量,按照其最大子类型的成员作为标准,从最大成员的整数倍开始储存。

看一下这个类,类Y中嵌套了类Xclass X
{int a;char b;double c;
};class Y
{char i;int j;short d;X k;
};

 在偏移量为0的位置放入i,在偏移量为4的位置放入4,偏移量为8的位置放入d,此时的偏移量为10变量K中最大的类型是double占据8个字节,10不能整除8,偏移量后移,直到偏移量为16时,放入a,之后放入b,在偏移量为24的位置放入c,最终大小为32个字节。

三、类的总大小是最大成员类型的整数倍,如果不是,需要在成员后继续填补,直到达到最大成员类型的整数倍。

看一下下面的代码class BIT
{int a;char b;
}

 这个类中数据占据5个字节,数据之间没有填补,但类的总大小是8个字节,按照规则三,类的大小是最大元素的整数倍,最大类型是4个字节,不能被5整除,所以在变量b之后还要继续填补三个字节。

四、如果程序中有#pragma pack(n)定义了字节,那么编译器会用n与数据大小做比较,两者中选择小的为偏移量。

类的大小的影响因素

一,系统是32位还是64位

数据类型32位64位
char11
char*48
short int22
int44
unsigned int44
float44
double88
long48
long long88
unsigned long48

二、成员变量的排列顺序 

class  A
{char a;char b;int  c;
}class  B
{char a;int  c;char b;
}

 同样的数据,顺序不同A的大小为8字节,B的大小为12字节。

让结构体按照指定的默认对齐数进行对齐

VS中,可以通过#pragma pack(n)预处理指令定义字节。

确定偏移量
大小端字节序

内存中每个字节作为一个存储单元对应一个唯一的编号,这个编号就是地址也就是指针,地址分为低地址与高地址,编号小的为低地址,大的为高地址。

数据的值分为高位和低位

大端存储模式:高位值放入低地址位

小端存储模式:低位值放入低地址位

当然需要注意的是,如果多个数据  0X12345678 0X11223344,不同的数据存储与大小端没有关系。

不同的处理器,大小端字节序不同,判断如何判断采用的是大端还是小端?

看一下下面的图不难发现,将int类型的1放入内存,只需要提取内存中0X00000000的数据,就可以判断是大端还是小端。

This指针

概念

先看一下下面代码:

class Date
{
public:void Init(int year, int month, int day);
private:int _year;int _month;int _day;
};
void Date::Init(int year, int month, int day)
{_year = year;_month = month;_day = day;printf("%d-%d-%d\n", _year, _month, _day);
}
int main()
{Date A;Date B;A.Init(2023, 10, 12);B.Init(2022, 10, 9);system("pause");return 0;
}

类中的函数存在于(常量区)只有一份,上面的代码中对象A和B分别调用了Init函数,输出的结果不同,这是因为在类中存在一个隐形的指针,this指针。

为了让成员函数知道操作哪一个对象的成员变量,C++增加了一个隐藏的指针this指针,当该指针指向了某个对象时,通过成员函数操作的内容就是该类的成员变量。 

this指针四大特性

一、成员函数内部使用

this指针只能在成员函数内部使用,C++定义时将this指针默认定义成了成员函数的第一个形参。

void Date::Init(Date* this,int year, int month, int day)
{this->_year = year;this->_month = month;this->_day = day;printf("%d-%d-%d\n", _year, _month, _day);
}

 本质上this指针只是个形参,接收实参(类的地址),完成相应的操作。

二、隐式指针

this指针作为形参不能显式(手动)写,C++自动完成的,一般通过ecx寄存器自动完成,实际在成员函数中可以在成员变量前填写this指针,不过没有必要。

三、类型

为了保护this指针的内容,C++定义它的类型为  类类型*const this,const修饰this指针,this指针的值不可被修改。

const int *pa = &a;
int const *pb = &a;
int *const pc = &a;*pa = 20; (不可修改指针指向的变量的值)
*pb = 30; (不可修改指针指向的变量的值)
*pc = 40; (可修改指针指向的变量的值)pa = &b; (可修改指针的值)
pb = &b; (可修改指针的值)
pc = &b; (不可修改指针的值)

四、存储位置

每一个对象,都有this指针,实际上就是它的地址,一般情况下this指针存储的在栈区中,VS编译器this指针存在ecx寄存器中。

一些关于this指针的问题

1、this指针的问题,下面两个题分别选择什么

题目一的选项是C、正常运行,p的指针是nullptr,print(p)调用后不发生解引用,直接打印print(),不发生解引用编译运行时不会崩溃。

题目二的选项时B、运行崩溃,P的指针是在传递后在cout<<this->_a<<endl处,发生了解引用,所以程序运行崩溃。

二、this指针放在哪里

this指针放在栈区中,VS编译器下this指针存放在ecx编译器中。

三、this指针可以为空吗

this指针可以为空,在不解引用时能正常使用,解引用时程序会崩溃。

总结

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

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

相关文章

docker-compose 部署示例

文章目录 docker-compose文件格式docker-compose 下载 docker-compose文件格式 这个软件的实际很小&#xff0c;只是根据配置文件产生一些docker命令来执行可以。 配置文件本身是yml的格式&#xff0c;如下 version: 3.5services:# Etherpad: real-time collaborative docume…

MQTT 主题通配符

MQTT 主题通配符 MQTT 主题通配符包含单层通配符 及多层通配符 #&#xff0c;主要用于客户端一次订阅多个主题。 注意&#xff1a;通配符只能用于订阅&#xff0c;不能用于发布。 单层通配符 加号 (“” ) 是用于单个主题层级匹配的通配符。在使用单层通配符时&#xff0c;…

鼎鑫鸿鄴利用国家的策略优势和满足全球需求并驾齐驱

随着全球对可再生能源的需求不断增长&#xff0c;鼎鑫鸿鄴新能源科技有限公司正充分利用中国政府的策略优势&#xff0c;积极满足全球能源使用需求&#xff0c;并在可再生能源领域崭露头角。中国属于全球最大的太阳能市场&#xff0c;在技术研发、产能建设和市场规模等方面拥有…

华为HCIP题库h12-821题库新增30题

901、 &#xff08;多选题&#xff09;下面关于BGP中的公认属性的描述&#xff0c;正确的是 A、公认必属性是所有BGP路由器都识别&#xff0c;且必须存在于Updata消息中 B、BGP必须识别所有公认属性 C、公认属性分为公认必遵和可选过渡两种 D、公认任意属性是所有BGP造由器…

[Spring] SpringMVC 简介(一)

目录 一、SpringMVC 简介 1、什么是 MVC 2、什么是 SpringMVC 3、SpringMVC 实现原理 4、SpringMVC 的特点 二、简单案例 1、引入依赖 2、在 web.xml 中配置前端控制器 DispatcherServlet 3、创建 SpringMVC 的配置文件 4、创建请求控制器 5、测试页面 6、访问不到 …

数学建模——人工神经网络模型

一、人工神经网络简介 1、神经网络起源与应用 1943年心理学家McCulloch和数学家Pitts提出神经元生物数学模型&#xff08;M-P模型&#xff09;&#xff0c;后来人工神经网络(Artifical Neural Network,ANN)是在生物神经网络(Biological Neural Network,BNN)基础上发展起来的&a…

网络通信错误代码列表 HTTP 、FTP

HTTP 1xx&#xff08;临时响应&#xff09;&#xff1a;表示临时响应并需要请求者继续执行操作的状态代码。 100 &#xff08;继续&#xff09; 请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分&#xff0c;正在等待其余部分。 101 &#xff08;切换协议…

Json的操作

Json解析float报错&#xff0c;要使用double 第一种 void Start(){//Convert();Convertddd();}public void Convertddd(){ //LineDataDic d new LineDataDic();JsonData d new JsonData();for (int i 0; i < 5; i){LineData convertData new LineData();convertData.ta…

【LeetCode】2578. 最小和分割

难度&#xff1a;简单 题目 给你一个正整数 num &#xff0c;请你将它分割成两个非负整数 num1 和 num2 &#xff0c;满足&#xff1a; num1和num2直接连起来&#xff0c;得到 num各数位的一个排列。 换句话说&#xff0c;num1 和 num2 中所有数字出现的次数之和等于 num 中…

Kestra:高性能、基于 Java 的编排平台

Kestra 是一个基于 Java 构建的事件驱动的编排和调度平台&#xff0c;它利用 YAML 进行工作流定义&#xff08;您可以将其视为工作流的 Terraform&#xff09;。 Kestra 可以简化计划和事件驱动的工作流程。通过将基础设施即代码最佳实践引入数据、流程和微服务编排&#xff0…

MobaXterm使sftp目录与cmd目录同步

MobaXterm使sftp目录与cmd目录同步 创建session时在ssh菜单栏中选择Advanced SSH settings其中SSH-browser type 选择SCP&#xff08;enhanced speed&#xff09; 勾选Follow SSH path

Red Hat 8 安装Docker返回找不到镜像的问题(Status code: 404)

文章目录 小结问题解决参考 小结 Red Hat 8 yum 指令安装Docker社区版时返回了Status code: 404错误&#xff0c;也就是找不到相应的仓库镜像&#xff0c;进行了解决。 问题 环境: Red Hat 8.3 首先安装了 yum install -y yum-utils配置Red Hat 8的Docker的镜像仓库&#x…

Ubuntu18.04中QT安装下载安装pcl和vtk以及使用过程中踩过的坑

一、先记录一下下载过程中踩过的坑 问题1&#xff1a;QVTKOpenGLNativeWidget和QVTKWidget 之前从来没有接触过QT中显示3D点云方面的知识&#xff0c;了解到可以用pcl&#xff0c;然后在网上各种找pcl下载的相关内容&#xff0c;想要在QT中显示出来&#xff0c;需要用到VTK&a…

TS(五):装饰器

装饰器 启用装饰器支持类装饰器定义并使用装饰器对比不使用装饰器装饰器叠加实现消息提示统一响应装饰器工厂 方法装饰器登录状态验证数据请求 属性装饰器大小写转换 元数据安装依赖基础用法 参数装饰器验证参数是否为必填项 启用装饰器支持 修改 tsconfig.json {"exper…

和鲸 ModelWhale 与华为 OceanStor 2910 计算型存储完成兼容性测试

数智化时代&#xff0c;数据总量的爆炸性增长伴随着人工智能、云计算等技术的发展&#xff0c;加速催化了公众对于数据存储与应用的多元化需求。同时&#xff0c;数据也是重要的基础资源和战略资源&#xff0c;需要严格保障其安全性、完整性。搭建国产数据基础设施底座&#xf…

信息系统项目管理师第四版学习笔记——高级项目管理

项目集管理 项目集管理角色和职责 在项目集管理中涉及的相关角色主要包括&#xff1a;项目集发起人、项目集指导委员会、项目集经理、其他影响项目集的干系人。 项目集发起人和收益人是负责承诺将组织的资源应用于项目集&#xff0c;并致力于使项目集取得成功的人。 项目集…

实验2.1.2 交换机的常用配置

项目2 交换技术的位置 活动2 交换机的常用配置 一、具体要求&#xff1a; &#xff08;1&#xff09;添加1台计算机&#xff0c;将标签名更改为PC1。 &#xff08;2&#xff09;添加1台S3700-26C-HI交换机&#xff0c;标签名为SWA&#xff0c;将交换机的名称设置为SWA。 &am…

AI:37-基于深度学习的安全帽检测方法研究

随着人工智能的快速发展,安全问题日益受到关注。在工业生产、建筑工地和其他危险环境中,安全帽的佩戴是预防头部伤害的重要措施。本文研究了基于深度学习的安全帽检测方法,通过分析图像数据中的头部和安全帽,实现了自动化安全帽检测和预警系统。 1.随着工业自动化的推进和…

华为云云耀云服务器L实例评测 | 实例评测使用之硬件参数评测:华为云云耀云服务器下的 Linux 磁盘目录分析神器 ncdu

华为云云耀云服务器L实例评测 &#xff5c; 实例评测使用之硬件参数评测&#xff1a;华为云云耀云服务器下的 Linux 磁盘目录分析神器 ncdu 介绍华为云云耀云服务器 华为云云耀云服务器 &#xff08;目前已经全新升级为 华为云云耀云服务器L实例&#xff09; 华为云云耀云服务器…

关键词搜索快手商品列表数据,快手商品列表数据接口,快手API接口

在网页抓取方面&#xff0c;可以使用 Python、Java 等编程语言编写程序&#xff0c;通过模拟 HTTP 请求&#xff0c;获取快手网站上的商品页面。在数据提取方面&#xff0c;可以使用正则表达式、XPath 等方式从 HTML 代码中提取出有用的信息。值得注意的是&#xff0c;快手网站…