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,一经查实,立即删除!

相关文章

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 创…

攻防世界——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…

【Springboot】日志

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

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

流程图&#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…

大英第四册课后翻译答案

目录 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项目…

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…

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;用于授权第三方应用程序…

Leetcode的AC指南 —— 栈与队列:225.用队列实现栈

摘要&#xff1a; **Leetcode的AC指南 —— 栈与队列&#xff1a;225.用队列实现栈 **。题目介绍&#xff1a;请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 …

简单了解AJAX

文章目录 1、什么是AJAX2、AJAX快速入门3、Axios异步框架3.1、Axios 快速入门3.2、Axios 请求方式别名 1、什么是AJAX 概念&#xff1a;AJAX(Asynchronous JavaScript And XML)&#xff1a;异步的 JavaScript 和 XML AJAX作用&#xff1a; 与服务器进行数据交换&#xff1a;通…

图卷积GCN实战基于网络结构图的网络表示学习实战

下面的是数据&#xff1a; from,to,cost 73,5,352.6 5,154,347.2 154,263,392.9 263,56,440.8 56,96,374.6 96,42,378.1 42,58,364.6 58,95,476.8 95,72,480.1 72,271,419.5 271,68,251.1 134,107,344.0 107,130,862.1 130,129,482.5 227,167,1425.7 167,298,415.7 298,209,42…

Unity3D学习之Unity基础——3D数学

文章目录 1. 前言2 Mathf和Math基础2.1 一般用于只计算一次的函数2.1.1 PI Π PI2.1.2 取绝对值 Abs2.1.3 向上取整 CeilToInt2.1.4 向下取整 FloorToInt2.1.5 钳制函数 Clamp2.1.6 获取最大值 Max2.1.7 获取最小值 Min2.1.8 一个数的n次幂 Pow2.1.9 四舍五入 RoundToInt2.1.10…

Spring Boot实现统一异常处理的技术解析

引言 在软件开发过程中&#xff0c;异常处理是非常重要的一环。一个好的异常处理机制可以帮助我们更好地定位问题&#xff0c;提高代码的可维护性和稳定性。Spring Boot作为一款轻量级的Java开发框架&#xff0c;提供了一种简单而高效的方式来实现统一异常处理。本文将详细介绍…

springboot 3 + mysql8 + flyway 数据库版本管理

1、flyway flyway官方文档地址&#xff1a;https://documentation.red-gate.com/fd 对于不怎么看文档的我来说&#xff1a; 1&#xff09;flyway是个管理数据库版本的工具&#xff0c;可以对不同环境的sql进行迁移操作。 2&#xff09;优点&#xff1a;初始化、后期数据的管理…

java使用jsch处理软链接判断是否文件夹

前言 这一次主要是碰到一个问题。因为使用jsch去读取文件的时候&#xff0c;有一些文件它是使用软链接制作的一个映射。因为这里面有一个问题。如果它是软链接你就无法判断他到底是文件。还是文件夹&#xff1f;因为他没有提供可以直接读取的方法&#xff0c;用权限信息去判断…

Nomogram文献分析:提取数据

前言 今天教大家如何分析Nomogram类型的文章&#xff0c;并使用我们开发的系统零代码提取数据。 系统地址&#xff1a;https://clinicaldata.fun/ 要分析的文章&#xff1a;https://pubmed.ncbi.nlm.nih.gov/36504658/ 。这是一篇典型的mimic-iii数据分析的套路&#xff0c;…

srm-50——攻防世界

可以知道这道题是二类题型&#xff0c;你完成某个事情给你flag 我们输入正确的东西&#xff0c;给“flag” 运行一下可以知道这些关键词 直接关键词在字符串里面 找到运行得到的东西 INT_PTR __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) {HMODULE Mo…