类实例化对象的存储与内存对齐,this指针与调用成员函数传参的本原面目(两种调用方式)

news2025/2/20 23:45:49

类的实例化对象的内存存储方式与内存对齐

  1. 对于类当中定义的成员函数,是放在公共代码区的,在公共代码区有类成员函数表
  2. 对于不同的实例化对象而言,它里面的各个成员变量都是不一样的,但是如果他们分别调用相同名字的成员函数,这些成员函数都是一样的,实际上会专门划一块公共区域存放这些成员函数,而不是到当中去每个对象去找。
    在这里插入图片描述
  3. 因此在类的实例化对象当中,是没有为该类的成员函数开辟空间,只有为该类的成员变量开辟空间
    在这里插入图片描述
  4. 当对类的某个实例化对象的成员变量进行访问的时候,是在访问这个实例化对象所占的内存空间,当对某个实例化对象.成员函数的时候,不会到这个实例化对象里面的内存空间去。
  5. C++为了和c保持统一性,也需要进行内存对齐。没有这些内存对齐的话,去访问数据会有效率的损失。对于不同的类的实例化对象,他们的成员变量是不一样的,它们有自己各自的内存空间。但是在类当中的成员函数是针对本类的专属套餐,所以说不同的实例化对象是可以进行共用的,如果说在每个实例化对象里面都放一个成员函数的话,因为本来这些成员函数都是可以在该类当中去专属使用,这样就会造成浪费,但每一个实例化对象里面去存放专属的成员变量,这是应该的。
  6. 反正成员函数不存在实例化对里面。
  7. 结构体内存对齐规则:然后由于在C++当中类是对c语言当中结构体的升级,学语言的发展必须是要向前兼容的。据说c++当中的类的各个成员变量也是需要进行内存对齐,至于具体的内存对齐的规则与c语言当中结构体内存对齐一模一样:
    在这里插入图片描述
  8. 为什么结构体内存对齐?计算机在内存当中读取数据的时候,并不是你想访问哪个字节就去访问哪个字节,一般一次固定访问四个字节一次读4个字节,32个位(这个就跟具体硬件有关系),反正就是由于硬件的具体设计,一次的话必须得读四个字节,不能你想读多少就读多少。比如说:在这里插入图片描述
  9. 内存对齐肯定都是以空间换时间。如果不想以空间换时间,就是宁愿程序跑的慢一点,但是空间十分珍贵,这时候就会出现什么修改默认对齐数啊等等,以时间换空间。
    在这里插入图片描述

sizeof计算类的实例化对象大小

  1. 注意:sizeof(类)与sizeof(该类的实例化对象)两者的结果是一样的,一个道理,然后在具体计算的时候是不考虑成员函数,只考虑成员变量。
  2. 因为对象里面只存储成员变量而不存储成员函数,所以对象的大小只计算成员变量,不计算成员函数
  3. 4,成员函数是放在公共代码区的,并不是放在类的实例化对象当中,因此成员函数是不占任何空间的,sizeof在计算类的实例化对象的时候,只计算成员变量的大小
class A1 
{
public:
	void f1()
	{
	}
private:
	int _a;
};
int main()
{
	cout << sizeof(A1) << endl;
	return 0;
}
  1. 16
class A
{
	void func()
	{
		cout << "Hello" << endl;
	}
	int b;
	char a;
	double c;
};
int main()
{
	cout << sizeof(A) << endl;
	return 0;
}

在这里插入图片描述
5. 24

class A
{
	void func()
	{
		cout << "Hello" << endl;
	}
	int b;
	char a;
	double c;
	char d;
};
int main()
{
	cout << sizeof(A) << endl;
	return 0;
}

在这里插入图片描述
6. 如果一个类没有成员变量(仅有成员函数或者说类中什么都没有,也就是空类),那么这个类的实例化对象也需要一个字节的空间,这一个字节的空间是为了占个位置,表示对象的存在,由于他没有成员变量,所以说不存储任何有效数据。但反正他就是有一个字节,取地址的话也是可以取得到的。
在这里插入图片描述
注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象

this 指针 【 类名* const this 】

  1. 在类当中的成员函数都是放在公共数据区当中,所以说如果说某一个类的两个不同实例化对象去调用相同名字的成员函数,实际上他们在调用的是同一个函数
  2. 这时候问题就来了,比如说他们都调用Print函数,由于这两个类的实例化对象当中的成员变量不一样,所以就打印出了不同的结果,问题是他们两个调用的都是同一个函数,为什么会出现不同的结果呢?
  3. 类当中的这些成员函数他们都是放在公共数据区当中,只要是这个类的,不管多少实例化对象去调用这个函数,你从汇编指令的角度去看,无非都是一模一样的call 一模一样的地址,我就去公共数据区当中去找到这个函数,执行函数里面的汇编指令,所以说调用的函数是完全一模一样的。
  4. C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
  5. 原因在于成员函数的参数这边有我们看不见的一个隐藏起来的this指针,一旦某个类的实例化对象去调用类的成员函数,对于成员函数需要传入参数,这个参数就会有一个隐藏的this指针,你就可以理解成编译器编译了之后会把成员函数给它改掉了,参数里面反正有一个this指针指针的类型是(类名*),然后对于这个成员函数里面的各个成员变量前面也都会用this指针->访问获取
    上面讲的这是一方面,然后在外面类的实例化对象,具体去调用成员函数的时候也会把实例化对象的地址传过去,这些都是隐藏起来的,悄悄搞得,暗箱操作,编译器搞得。所以说调用的就是同一个函数,只不过它们的形参不同,所以说结果也不同。
    在这里插入图片描述
    在这里插入图片描述
  6. this指针是一个暗箱操作的罪魁祸首,他不能在成员函数的形参和实参当中去显示传递。但却能够在成员函数内部去显示使用。以后会有很大用途
    在这里插入图片描述
  7. 并且这个this指针还不能去修改,它的类型实际上是这样的 (类名)* const 。所以说他自己不能被改,但是他指向的东西是可以被修改的。
    在这里插入图片描述
  8. this指针形参与实参不能显示传递

从汇编与函数栈帧底层角度的一些认识

  1. This指针是隐藏的,所以说对于类的实例化对象在调用类的成员函数当中,比如说你的形参有三个,但实际上他是有四个。这些形参在所属函数被调用之前都会被压参压到栈里面去。但实际上对于this指针的话,编译器会进行优化,如果你频繁的去调用成员函数的话,那么这个this指针就需要频繁的去传入,在vs下面对this指针传递进行优化。
  2. 从函数栈帧底层的角度去理解的话,如果你要调用一个函数,那么在函数栈帧建立之前,先要把他的参数先压到栈区里面,然后等到具体函数栈帧建立完了,然后里面函数具体执行汇编代码的时候,会回过头来去找你这些已经事先压在栈里面的参数。当类的实例化对象调用成员函数的时候,这个this指针压参是通过寄存器,也就是说把类的对象的地址放在寄存器当中,通过寄存器去传参,因为寄存器相比于内存快太多了。
    在这里插入图片描述
    在这里插入图片描述

问:this指针存在哪边?

  1. 首先,这个指针不可能存在对象里面,假设他存在对象里面,那为什么用sizeof计算它大小的时候没有把这个指针给他算进去。
  2. this指针相当于是类当中成员函数的一个形参(被隐藏掉了,你看不见而已),当然不是实参,因为实参是对象的地址。
  3. this是指针成员函数的形参,根据函数栈帧的知识,刚说你形参要传入到函数的时候,需要去压栈,这个形参是作为函数栈帧的一部分,就是跟普通参数一样存在函数调用的函数栈帧里面
  4. 但并不是在实例化对象的内存区域当中。然后当函数调用结束的时候,这个形参this它自然也会被销毁掉。
  5. 所以在内存栈区。

问:下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void Print()
	{
		cout << "Print()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

C

  1. 易错点:因为类当中的成员函数它并不是在类的实例化对象当中,而是在公共数据段,也就是公共代码区当中。所以说如果说对象指针去->成员函数,这个指针是不需要去解引用的。因为print的地址根本就不在对象当中,而是在公共代码块当中,所以说在编译的时候的地址很容易找的到的。既然在公共代码段当中很容易找到这个函数的地址,那么在编译的时候直接汇编call xxxxxxx。
  2. 然后这个实例化对象指针p会作为实参去传递给成员函数。
  3. 如果说一个是实例化对象类型指针p去用一个箭头去访问一个成员变量的话,是需要到这个对象当中的内存空间里面去寻找的,这时候就需要对这个指针进行解引用操作,然后如果说这时候这个指针是空指针,那就麻烦了。
  4. 但如果说一个对象指针需要去访问一个成员函数,但成员函数是在内存当中的数据区的,所以说在编译的时候转化为汇编指令的时候是不需要到对象的内存空间当中去寻找,直接在内存的公共代码区中就可以找得到,所以就算是空指针也不会报错。

问:下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
void PrintA()
{
cout<<_a<<endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
return 0;
}

B
在这里插入图片描述
在这里插入图片描述

问:为什么这样写不可以 : 类名::成员函数();

  1. 虽然这个符号它确实是域作用限定符,并且类名确实是类域的名称。
  2. 但是当你这样写的时候,你这个成员函数的this指针传什么参数,根本就没有一个实例化对象,也就意味着根本就没有这个对象的地址,所以说这个函数就传不了参数,所以就会报错。

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

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

相关文章

cmd切换壁纸 适用windows10

文章目录 代码代码讲解参考文章菜鸟的目录结构注意 昨天菜鸟上班但是真的没活干&#xff0c;闲着无聊&#xff0c;突然发现自己壁纸好久都是一个&#xff0c;看着真的烦了&#xff0c;但是下载一个壁纸软件又感觉实际用处不大还占着内存&#xff0c;所以菜鸟就想&#xff0c;要…

Java Type接口出现的原因以及它和泛型的关系

Java泛型很多人都用过&#xff0c;但是对于其中的原理可能很多人可能都不太清楚。 首先给出一个结论&#xff1a;Java的泛型是伪泛型&#xff0c;因为JVM在编译以后会将所有泛型参数擦除掉&#xff0c;这个就叫类型擦除。 下面用一段代码来证明&#xff0c;毕竟千言万语BB不如…

【软考数据库】第三章 数据结构与算法

目录 3.1 数据结构 3.1.1 线性结构 3.1.2 数组 3.1.3 矩阵 3.1.4 树与二叉树 3.1.5 图 3.2 查找 3.2.1 顺序查找 3.2.2 折半查找 3.2.3 哈希表 3.3 排序 3.3.1 直接插入排序 3.3.2 希尔排序 …

Win10任务栏卡死怎么办?这3个方法快收藏!

案例&#xff1a;win10任务栏卡死 【姐妹们&#xff0c;我的win10任务栏一直卡着&#xff0c;我完全没法使用计算机了&#xff0c;遇到这种情况&#xff0c;我应该怎么做呢&#xff1f;求大家给我支支招&#xff01;感谢感谢&#xff01;】 我们使用电脑的过程中&#xff0c;…

MyBatis的添加和简单使用

什么是MyBatis mybatis是一个方便我们更简单的操作数据库的框架&#xff0c;让我们不用再使用JDBC操作数据库。 MyBatis的创建 老项目添加mybatis&#xff0c;首先要安装好editstarters插件&#xff0c;然后在pom.xml中右键generate选择edit插件&#xff0c;注意不仅要添加m…

多维时序 | MATLAB实现BO-CNN-BiLSTM贝叶斯优化卷积双向长短期记忆网络数据多变量时间序列预测

多维时序 | MATLAB实现BO-CNN-BiLSTM贝叶斯优化卷积双向长短期记忆网络数据多变量时间序列预测 目录 多维时序 | MATLAB实现BO-CNN-BiLSTM贝叶斯优化卷积双向长短期记忆网络数据多变量时间序列预测效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 基于贝叶斯优化卷…

C/C++|物联网开发入门+项目实战|宏定义|数据声明|位操作|类型修饰符|访问固定内存位置|嵌入式C语言高级|常见面试题目讲解-学习笔记(13)

文章目录 常见面试题目讲解宏定义数据声明类型修饰符的使用总结位操作访问固定内存位置 参考&#xff1a; 麦子学院-嵌入式C语言高级-C语言函数的使用-常见面试题目讲解 参考&#xff1a; 嵌入式程序员应该知道的0x10个基本问题 常见面试题目讲解 宏定义 1 .用预处理指令#d…

ERD Online 4.1.0对接ChatGPT,实现AI建模、SQL自由

ERD Online 是全球第一个开源、免费在线数据建模、元数据管理平台。提供简单易用的元数据设计、关系图设计、SQL查询等功能&#xff0c;辅以版本、导入、导出、数据源、SQL解析、审计、团队协作等功能、方便我们快速、安全的管理数据库中的元数据。 4.1.0 ❝ :memo: fix(erd): …

CARIS11.3使用一段时间后的经验和总结

虽然CARIS11.4存在一些小bug&#xff0c;但CARIS11.3使用没有什么问题&#xff0c;相对于CARIS9而言&#xff0c;在导入数据和程序界面有些改进。用过CARIS9的同学都知道其建立项目和导入数据的步骤比较繁琐。而CARIS11.3导入数据的过程比较简洁&#xff0c;基本步骤如下&#…

把阿里大鸟花3个月时间整理的软件测试面经偷偷给室友,差点被他开除了···

写在前面 “这份软件测试面经看起来不错&#xff0c;等会一起发给他吧”&#xff0c;我看着面前的面试笔记自言自语道。 就在这时&#xff0c;背后传来了leder“阴森森”的声音&#xff1a;“不错吧&#xff0c;我可是足足花了三个月整理的” 始末 刚入职阿里的我收到了大学…

牛客网Verilog刷题——VL2

牛客网Verilog刷题——VL2 题目答案 题目 要求用verilog实现两个串联的异步复位的T触发器的逻辑&#xff0c;如下图所示。   模块的输入输出信号如下表&#xff0c;需要注意的是&#xff1a;这里rst是低电平复位&#xff0c;且采用异步复位的方式复位。 信号类型输入/输出c…

2023年淮阴工学院五年一贯制专转本大学语文考试大纲

2023年淮阴工学院五年一贯制专转本大学语文考试大纲 一、考试目标 淮阴工学院五年一贯制高职专转本入学考试秘书学专业《大学语文》考试是我校为招收五年一贯制高职专转本学生设置的具有选拔性质的考试科目。其目的是科学、公平、有效地测试考生是否具备攻读秘书学本科学位所…

( “树” 之 BST) 530. 二叉搜索树的最小绝对差 ——【Leetcode每日一题】

二叉查找树&#xff08;BST&#xff09;&#xff1a;根节点大于等于左子树所有节点&#xff0c;小于等于右子树所有节点。 二叉查找树中序遍历有序。 ❓ 530. 二叉搜索树的最小绝对差 难度&#xff1a;简单 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同…

特征选择算法 | Matlab 基于无限潜在特征选择算法(ILFS)的分类数据特征选择

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 特征选择算法 | Matlab 基于无限潜在特征选择算法(ILFS)的分类数据特征选择 部分源码 %

Vite 4.3 is out!

原文地址 本次迭代中&#xff0c;我们专注于改善开发服务器的性能。我们优化了解析逻辑&#xff0c;改进了热路径&#xff0c;并实现了更智能的缓存&#xff0c;用于查找 package.json、TS 配置文件和解析的 URL 等。 你可以在 Vite 的贡献者之一的博客文章中详细了解本次性能…

数据结构之二分搜索树

树在我们底层结构中是被广泛运用的,但是为什么会选择它却是我们需要了解的东西,接下来 让我们一起走进树的世界 请看下图&#xff1a; 在我们生活中&#xff0c;有很多关于树的存在&#xff0c;比如电脑中的磁盘&#xff08;C D盘&#xff09;&#xff0c;在文章中写的目录都是…

LangChain与大型语言模型(LLMs)应用基础教程:记忆力组件

如果您还没有看过我之前写的两篇博客&#xff0c;请先看一下&#xff0c;这样有助于对本文的理解&#xff1a; LangChain与大型语言模型(LLMs)应用基础教程:Prompt模板 LangChain与大型语言模型(LLMs)应用基础教程:信息抽取 LangChain与大型语言模型(LLMs)应用基础教程:角色…

在线甘特图制作教程

在线甘特图制作教程 很多的甘特图工具都是需要下载到本地&#xff0c;并且做好了之后也不方便分享给别人。给大家分享一个在线的甘特图制作工具 不需要登录注册 知竹甘特图 https://www.yxsss.com/ 打开知竹甘特图 https://www.yxsss.com/gatt/3b7d1ecb7211b9473e7d1ecb72 …

015:Mapbox GL绘制修改多边形,实时更新面积

第015个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中添加draw组件,绘制多边形,编辑多边形,实时显示面积值。这里使用turf来计算面积值。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源代码(共92行)安装…

ASP.NET Core MVC 从入门到精通之wwwroot和客户端库

随着技术的发展&#xff0c;ASP.NET Core MVC也推出了好长时间&#xff0c;经过不断的版本更新迭代&#xff0c;已经越来越完善&#xff0c;本系列文章主要讲解ASP.NET Core MVC开发B/S系统过程中所涉及到的相关内容&#xff0c;适用于初学者&#xff0c;在校毕业生&#xff0c…