this指针相关

一、类对象的存储方式

先说一下结论:一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐
注意空类没有成员变量的类的大小编译器给了这两种类一个字节来唯一标识这个类的对象。

class A
{
public:int _a;int _b;
};
class B
{// 空类
};
class C
{
public:void func(){cout << "func()" << endl;}
};
int main()
{cout << "A的大小:" << sizeof(A) << endl;cout << "B的大小:" << sizeof(B) << endl;cout << "C的大小:" << sizeof(C) << endl;return 0;
}

  • 为什么成员变量存放在在类对象中,成员函数不在类对象中?

成员变量存放在类对象中,每个类对象都会拥有自己的成员变量。这些成员变量占据了每个对象的内存空间,它们具有对象的特定值和状态。当创建多个对象时,每个对象都会有自己独立的成员变量,从而保证了数据的封装性。

相比之下,成员函数并不包含对象特定的数据,它们通常只需要访问类的成员变量以及执行一些操作。因此,将成员函数与对象实例分离可以节省内存空间,避免重复存储相同的函数代码。

另外,将成员函数与对象实例分离还能提高代码的复用性。多个对象可以共享同一个类的成员函数,而无需为每个对象都存储一份相同的函数代码。这样可以减少内存消耗,并且方便维护和修改代码。

总结起来,将成员变量存放在类对象中,而将成员函数与对象实例分离,能够节省内存空间、提高代码复用性,并符合面向对象编程的封装性原则。

补充:内存对齐的规则

1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。VS中默认的对齐数为8。
3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
 

二、this指针

  • 既然内存中不存放成员函数,那么程序又是怎么确定是哪个对象调用的函数呢?
class Date
{
private:int _year;int _month;int _day;
public:Date(int year = 2024, int month = 1, int day = 14){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
};int main()
{Date d1(2023, 12, 12);Date d2;d1.Print();d2.Print();return 0;
}

在C++中,每个成员函数都有一个隐含的额外参数,即指向调用该函数的对象的指针(this指针)。通过this指针,程序能够确定是哪个对象调用了该函数。

当调用一个成员函数时,编译器会自动将调用该函数的对象的地址作为this指针传递给函数。这样,在函数内部就可以通过this指针来访问对象的成员变量和其他成员函数。

所以上面代码就会被编译器处理成这样:

void Print()
{cout << _year << "/" << _month << "/" << _day << endl;
}void Print(Date* this)
{cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
}d1.Print();
d2.Print();d1.Print(&d1);
d2.Print(&d2);
  • this指针的特性

1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。

2. 只能在“成员函数”的内部使用
3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

总结:

1.this指针是一个隐含于每一个非静态成员函数中的特殊指针。它指向正在被该成员函数操作的那个对象。(全局函数没有this指针
2.当对一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,然后调用成员函数,每次成员函数存取数据成员时,由隐含使用this指针。
3.当一个成员函数被调用时,自动向它传递一个隐含的参数,该参数是一个指向这个成员函数所在的对象的指针。
4.this指针被隐含地声明为:Class Name* const this,这意味着不能给this指针赋值;

在Class Name 类的const成员函数中,this指针的类型为:const className * const,这说明对this指针所指向的这种对象是不可修改的(即不能对这种对象的数据成员进行赋值操作);
5.this并不是一个常规变量,而是个右值,所以不能取得this的地址(不能&this)。
6.在以下场景中,经常需要显式引用this指针
ⅰ.为实现对象的链式引用;
ⅱ.为避免对同一对象进行赋值操作
iⅱ.在实现一些数据结构时,如list。

  • this相关题目

1、下面描述错误的是( D )

A.this指针是非静态成员函数的隐含形参.

B.每个非静态的成员函数都有一个this指针.

C.this指针是存在对象里面的.

D.this指针可以为空

在C++中,this指针始终指向当前对象的地址,它是非静态成员函数的隐含形参。this指针不可能为空,因为它指向调用该成员函数的对象的地址。在非静态成员函数中,this指针可以用于访问该对象的成员变量和成员函数。

2、下列有关this指针使用方法的叙述正确的是( D )

A.保证基类保护成员在子类中可以被访问

B.保证基类私有成员在子类中可以被访问

C.保证基类公有成员在子类中可以被访问

D.保证每个对象拥有自己的数据成员,但共享处理这些数据的代码

this指针并不影响对基类成员的访问权限,它仅仅指向当前对象,无论是基类还是子类的成员。保护成员只能在派生类内部或友元函数中访问,私有成员只能在类内部访问,而公有成员可以在任何地方访问。this指针不会改变这些访问权限。

"共享处理这些数据的代码"指的是非静态成员函数中对对象的数据进行处理的代码段,这段代码可以被多个对象共享使用。换句话说,通过this指针,每个对象可以调用同一个非静态成员函数来处理自己的数据成员,这样就避免了为每个对象都复制一份相同的代码。

例如,假设有一个类Person,其中包含一个非静态成员函数printName()来打印该对象的姓名。当创建多个Person对象时,这些对象共享同一个printName()函数的代码,但通过各自的this指针,每个对象可以将自己的姓名传递给该函数进行打印,从而实现了数据的共享处理。

3、在C++函数中,有些函数是没有this指针的:

  1. 全局函数不具备this指针
  2. static函数不具备this指针
  3. 友元函数不具备this指针

空指针问题

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

1、

class A
{
public:void Print(){cout << "Print()" << endl;}
private: int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}

在执行 p->Print(); 这一语句时,其实执行的是A::Print(),因为p是一个类A的指针,所以编译器会在类A中查找是否存在Print()函数,发现类中存在这个函数则编译成功。

之后就进入运行阶段,虽然this指针为nullptr,但是Print()函数中没有执行对this解引用的操作,所以可以运行成功。

2、

class A
{
public:void PrintA(){cout << _a << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->PrintA(); return 0;
}

同样的执行A::Print(),执行函数,在函数内部存在对this指针解引用的操作 this->_a ,所以运行崩溃。


今天的分享就到这里了,如果,你感觉这篇博客对你有帮助的话,就点个赞吧!感谢感谢……

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

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

相关文章

【RL】(task3)A2C、A3C算法、JoyRL

note 文章目录 note一、A2C算法二、A3C算法时间安排Reference 一、A2C算法 在强化学习中&#xff0c;有一个智能体&#xff08;agent&#xff09;在某种环境中采取行动&#xff0c;根据其行动的效果获得奖励。目标是学习一种策略&#xff0c;即在给定的环境状态下选择最佳行动&…

Python多线程—threading模块

参考&#xff1a;《Python核心编程》 threading 模块的Thread 类是主要的执行对象&#xff0c;而且&#xff0c;使用Thread类可以有很多方法来创建线程&#xff0c;这里介绍以下两种方法&#xff1a; 创建 Thread 实例&#xff0c;传给它一个函数。派生 Thread 的子类&#xf…

计算机体系结构——多处理机系统

一、概述 重要概念 评估指标 通信延迟 通信延迟&#xff1d;发送开销&#xff0b;跨越时间&#xff0b;传输延迟&#xff0b;接收开销 跨越时间 数字信号从发送方的线路端传送到接收方的线路端所经过的时间。 传输时间 全部的消息量除以线路带宽。 多处理机的架构 根…

Unity 之 Addressable可寻址系统 -- HybridCLR(华佗)+Addressable实现资源脚本全热更 -- 实战(二)

Unity 之 Addressable可寻址系统 -- HybridCLRAddressable实现资源脚本全热更 -- 实战 前言实现原理一&#xff0c;HybridCLR相关操作1.1 安装HybridCLR1.2 打包程序集1.2 设置面板1.3 补充元数据1.4 代码加载流程 二&#xff0c;Addressable资源管理2.1 生成热更代码资源2.2 创…

【0246】深入分析PG内核Write-Ahead Log的实现机制

文章目录 1. 前言2. Write-Ahead Log2.1 WAL数据结构2.1.1 逻辑结构(Logical Structure)2.1.2 物理结构(Physical Structure)3. 参考文献1. 前言 Write-Ahead Log简写为WAL,即预写式日志,PG数据库内核引入WAL的原因基于以下几点: (1)如果发生停电、操作系统错误或数据…

攻防世界——answer_to_everything-writeup

__int64 __fastcall not_the_flag(int a1) {if ( a1 42 )puts("Cipher from Bill \nSubmit without any tags\n#kdudpeh");elseputs("YOUSUCK");return 0LL; } kdudpeh这个东西&#xff0c;根据题目提示sha1加密 import hashlib flagkdudpeh x hashlib…

网安防御保护入门

常见的网络安全术语&#xff1a; 漏洞&#xff08;脆弱性&#xff09;&#xff1a;可能被一个或多个威胁利用的资产或控制的弱点 攻击&#xff1a;企图破坏、泄露、篡改、损伤、窃取、未授权访问或未授权使用资产的行为 入侵&#xff1a;对网络或联网系统的未授权访问&#xff…

【Springboot】日志

1.日志的使用 日志主要用于记录程序运行的情况。我们从学习javase的时候就使用System.out.println();打印日志了&#xff0c;通过打印的日志来发现和定位问题&#xff0c;或根据日志来分析程序运行的过程。在Spring的学习中,也经常根据控制台的⽇志来分析和定位问题 。 日志除…

k8s-pvc/pv扩容记录

背景 一次聊天过程中&#xff0c;对方提及pvc的扩容&#xff0c;虽然有注意过 storageclass 有个AllowVolumeExpansion的配置&#xff08;有些csi插件是不支持该配置的&#xff0c;比如local-volume-provisoner&#xff09;&#xff0c;但是没有实际用过&#xff0c;所以还是心…

数据分析实战:城市房价分析

流程图&#xff1a; 1.读数据表 首先&#xff0c;读取数据集。 CRIMZNINDUSCHASNOXRMAGEDISRADTAXPTRATIOBLSTATtarget0.00632182.3100.5386.57565.24.09129615.3396.94.98240.0273107.0700.4696.42178.94.9671224217.8396.99.1421.60.0272907.0700.4697.18561.14.9671224217…

【MySQL数据库专项 一】一个例子讲清楚数据库三范式

好的&#xff0c;让我们以学校数据库中的一个表为例来说明第一范式&#xff08;1NF&#xff09;、第二范式&#xff08;2NF&#xff09;和第三范式&#xff08;3NF&#xff09;的概念。 什么是数据库三范式 数据库的范式&#xff08;Normalization&#xff09;是一组关于数据…

UI -- Vue2

Vue2 模板 Vue2 UI package.json同级components/slButton/element.vue <template><div class"d1"><span>测试123</span></div> </template><script>export default {name:"sl-button",data() {return {};}} …

大英第四册课后翻译答案

目录 Unit 1Unit 2Unit 3Unit 4小结&#xff1a; Unit 1 中庸思想&#xff08;Doctrine of the Mean&#xff09;是儒家思想的核心内容。孔子所谓的“中”不是指“折中”&#xff0c;而是指在认识和处理客观事物时的一种“适度”和“恰如其分”的方法。孔子主张不仅要把这种思…

街机模拟游戏逆向工程(HACKROM)教程:[14]68K汇编-标志寄存器

在M68K中&#xff0c;有许多条件分支指令&#xff0c;和jmp指令一样也会修改PC达到程序跳转或分支的目的&#xff0c;不过这些会根据一些情况或状态来选择是否跳转。而在M68K中&#xff0c;有一个特别的寄存器来标记这些情况。 CCR(状态标志寄存器) CCR寄存器是用来保存一些对…

微前端-无界wujie

无界微前端方案基于 webcomponent 容器 iframe 沙箱&#xff0c;能够完善的解决适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等用户的核心诉求。 主项目安装无界 vue2项目&#xff1a;npm i wujie-vue2 -S vue3项目…

HttpServletRequest getHeader、getHeaders、getIntHeader、getDateHeader区别

request.getHeader(“name”)&#xff1a; 获取请求头中指定名称的单个值&#xff0c;多个值时通常是返回最先出现的那个值 String contentLength request.getHeader("Content-Length"); request.getHeaders(“name”)&#xff1a; 获取请求头中所有具有指定名称…

77. 组合 - 力扣(LeetCode)

题目描述 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 输入示例 n 4, k 2输出示例 [[2,4],[3,4],[2,3],[1,2],[1,3],[1,4], ]解题思路 我们使用回溯、深度优先遍历的思想&#xff0c;我们使用一个栈 path…

Kotlin的数据类

引言 我们在做项目中涉及到各种数据类的处理&#xff0c;很多很杂乱。难免一个人的知识点有盲点&#xff0c;所以想着做个整理。 定义 在平时的使用中&#xff0c;我们会用到一些类来保持一些数据或状态&#xff0c;我们习惯上成为bean或者entity&#xff0c;也有的定义为mod…

SpringSecurity+OAuth2.0 搭建认证中心和资源服务中心

目录 1. OAuth2.0 简介 2. 代码搭建 2.1 认证中心&#xff08;8080端口&#xff09; 2.2 资源服务中心&#xff08;8081端口&#xff09; 3. 测试结果 1. OAuth2.0 简介 OAuth 2.0&#xff08;开放授权 2.0&#xff09;是一个开放标准&#xff0c;用于授权第三方应用程序…

【笔记】Helm-3 主题-13 Helm v2迁移到 v3

Helm v2 迁移到 v3 该指南介绍如何将Helm v2迁移到v3.Helm v2需要被安装且在一个或多个集群中管理版本。 Helm 3变化概述 Helm 2 to 3完整的变化列表在FAQ部分。以下是用户在迁移之前应该要注意的一些改变的概述&#xff1a; Helm | Docs 1.移除了Tiller&#xff1a; 1、用…