C++相关概念和易错语法(3)(类的声明和定义、空指针分析、this指针)

1.类的声明和定义

注意类的声明和定义分离的时候,在定义处要使用域作用限定符,否则函数声明链接时的定位不到函数的定义。

1b2a658133f843b588e0ef27bacdcf35.png

这些成员变量、函数的作用于这个类域,将功能集成在一起,这体现出封装的思想。

在区分类的定义和声明时,主要看有没有开辟空间

fadb2f62b8bc430f82d64960ba7f5010.png

在.h文件中,成员变量和成员函数都算作声明,只有在创建这个类的时候,才会为成员变量创建空间。但是,成员函数并不会被拷贝。这样可以防止空间的浪费。

为形象理解,可以将类的声明视为图纸,这个图纸可以实例出多个对象。

583ad0aee8564309afff382382f878c9.png

因此在计算对象的大小时,只会计算成员变量的大小,同时满足和结构体一样的对齐操作,当然你也可以用#pragma pack(1)来设置默认对齐数。

abb5da0e062d44e58ff06c7aa48757b4.png

注意这是64位平台测试,指针的大小是8个字节。

我们可以将成员函数视为类的公共区域,每个成员调用成员函数都是直接到类里面来找。注意刚刚的描述是便于形象理解成员函数的调用,和访问限定符(protected、struct默认公有public,class默认私有private,只要不写public都是私有)不同,不要混淆。208ae056096c408fadbedd86587e12ba.png

2.因空指针导致的程序崩溃

解释下面代码为什么不报编译错误:

f324d9a4ade44dc4bc26a3aa977393e8.png

我们需要通过编译的过程来解释这一现象:

cf54f11a320b4ebeab67bc931a3c052f.png

预处理是将所有的宏和头文件展开,生成的文件我们仍然能读懂。

编译是检查语法错误,语义是否能被正确解读。在这里,nullptr的使用并没有导致语法的错误,也不会产生歧义,所以编译这里不会报错。

汇编是将所有代码转化为二进制的机器指令。

 

同样,在链接时也不会出现问题,生成可执行程序。

2c8fc04bb2b749158c11caf25be24040.png

最终是因为越界访问导致程序崩溃。

注意导致程序崩溃的原因是对空指针的指向区域进行的访问或修改。如果不进行这些操作,那么就是可行的。引用就是个很好的例子。

49b2bf8382bc4d2797ee70ae58b23e66.png

因为引用的语法和实质层面的不一致,导致这里很容易被误解为对a进行了访问但因为引用的实质是指针,所以这里只是将a的值nullptr赋给了b,并没有对nullptr产生访问行为,所以这里的程序不会有任何问题。

669b1a8949fa435fa0a80110ea875e29.png

在观察程序崩溃时,先看语法层面上是否造成歧义,导致编译错误;再看要使用的函数是否都成功定义且定位,这关系到链接错误;最后从汇编的角度来看程序是否发生了越界访问等。

3.不同的this指针区分不同的对象

this是一个关键字。它是隐含在类中的一种指针,在对该类实例化出多个对象时,this指针就用来给每个对象贴上标签。

为了理解它,先看一段代码,解释为什么两次调用Add时都没有传参,但在类里面调用函数时还是能区分不同的对象:


#include <iostream>
using namespace std;class C
{
public:void Init(int a = 0, int b = 0, int c = 0){_a = a, _b = b, _c = c;}void Add(){cout << "add:" << _a + _b + _c << endl;}private:int _a;int _b;int _c;
};int main()
{C c1, c2;c1.Init(1, 2, 3);c2.Init(4, 5, 6);c1.Add();c2.Add();return 0;
}

结果是:

e366a1ee1fda40539969e4c09dd632db.png

其中虽然我们看上去没有传参,但是在汇编代码中我们就可以看到实际上Init和Add都多传了一个参数,这个参数就是this指针,在这里它的类型是C* const c1,C* const c2:

bcc4ad6f55be4795b92b2be5c4e36d35.png

70db2ff4719d43828331662fdfec1213.png

在代码语义上,它们相当于在参数中,多传了一个类的指针:

24f152a837b24123a120b93efabbebfb.png

e529727515bf495c92f9340fb7d87216.png

在实际写代码的时候,虽然this指针实际存在,但参数中却不能写this,因此这里使用注释来表示实际的执行情况。但是,在成员函数内部,可以显式写出this指针,因为this指针其实是类的指针,而类又和struct同源,所以用的是this->形式。

又因为this是成员的标签,它也不能随便更换其指向。

6602a6658e09482e9e60f6a4bd363687.png

 

this指针可能存在栈中,也可能存在寄存器中,不同编译器有不同的做法。但this指针都不会存在成员中。这可以用空类来进行验证。

b301fbf6401c46a2ac6fb6cb8c9d2440.png

如果指针确实存在成员中,那么这个类的大小至少是8(64位),所以this指针是单独在栈或寄存器存放的。而空类的大小为1是作为创建类成功的标志,对于没有成员变量的类都是如此

4.this指针为空指针的代码解读

先来看一段代码


#include <iostream>
using namespace std;class C
{
public:void Print(){cout << "Hello,world!" << endl;}
private:int _a;
};int main()
{C* c1 = nullptr;c1->Print();return 0;
}

运行结果是:

2176d1f027ec4888ac87a4ed853ee344.png

可以看出这个代码执行没有任何问题。

这要结合上面第2点对空指针的分析方法来判断。分析如下图:

425fab13e4ce4694a86eb4cc87eba162.png
 

 

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

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

相关文章

Vue3_2024_7天【回顾上篇watch常见的后两种场景】___续

Vue3中监听多条数据的两种使用 1.watch【使用上一章写法&#xff0c;监听两个属性&#xff0c;然后执行相应操作…】 2.watchEffect【相对于使用watch&#xff0c;watchEffect默认页面初始加载&#xff0c;有点类似加配置&#xff1a;立即执行 immediate】 代码&#xff1a; …

这个故事有点长 - 东方绿舟

这个故事有点长 - 东方绿舟 这个地方很大&#xff0c;游玩一天是没有问题。东方绿舟的1号门入口处&#xff0c;是一个人工瀑布&#xff0c;上边写着东方绿舟几个大字。远远看去&#xff0c;这个瀑布非常壮观&#xff0c;水的流淌让人感到凉爽&#xff0c;很适合在那里拍照打卡。…

使用注意力机制的 LSTM 彻底改变时间序列预测

目录 一、说明二、LSTM 和注意力机制简介三、为什么要将 LSTM 与时间序列注意力相结合&#xff1f;四、模型架构训练与评估 五、验证六、计算指标七、结论 一、说明 在时间序列预测领域&#xff0c;对更准确、更高效的模型的追求始终存在。深度学习的应用为该领域的重大进步铺…

喜讯 ChatGPT 3.5 免登录|免注册就可以使用了

https://chat.openai.com/ 直接访问openai 官网直接使用&#xff0c;当然还是要魔法的&#xff0c;不用再去用别人二次开发的&#xff0c;还有次数限制&#xff0c;还有开会员&#x1f605;才能用的。&#x1f600;试用啦一下&#xff0c;基本秒回答&#xff0c;能力也是在线的…

【Python】无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称解决方案

【Python】无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称解决方案 大家好 我是寸铁&#x1f44a; 总结了一篇【Python】无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称解决方案✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 今天寸铁…

渗透测试练习题解析 5(CTF web)

1、[安洵杯 2019]easy_serialize_php 1 考点&#xff1a;PHP 反序列化逃逸 变量覆盖 【代码审计】 通过 GET 的方式获取参数 f 的值&#xff0c;传递给变量 function 定义一个过滤函数&#xff0c;过滤掉特定字符&#xff08;用空字符替换&#xff09; 下面的代码其实没什么用…

【Java】jdk1.8 Java代理模式,Jdk动态代理讲解(非常详细,附带class文件)

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 一、什么是代理模式 想要学代理模式&#xff0c;我们就要先弄清一个概念“什么是代理”&#xff1f; 在我们的现实生活中&#xff0c;你或许不少听过关于代理的名词&#xff0c;如&#xff1a;代理商。那什么又叫做代理…

Rust---复合数据类型之结构体

目录 结构体的使用输出结果 结构体简化创建结构体更新语法元组结构体单元结构体&#xff08;unit struct&#xff09;结构体中的引用使用#[derive(Debug)]再次介绍 代码综合展示 与元组不同的是&#xff0c;结构体可以为内部的每个字段起一个富有含义的名称&#xff0c;因此无需…

【74LS191/48为可预置的四位二进制加/减法计数器3-9循环显示】2022-3-19

缘由我有电路原理图&#xff0c;想用proteus仿真&#xff0c;但是数码管不亮-嵌入式-CSDN问答 74LS191为可预置的四位二进制加/减法计数器 74ls191引脚功用 RCO进位/借位输出端 MAX/MIN进位/借位输出端 CTEN计数操控端 QA-QD计数输出端 U/D计数操控端 CLK时钟输入端 LO…

10-用PySpark建立第一个Spark RDD

目录 RDD概念RDD特点建立RDD的方式不同工具建立RDD的方式使用PySpark Shell(交互环境)建立RDD使用VSCode编程建立RDD使用Jupyter Notebook建立RDD 总结 PySpark实战笔记系列第一篇 RDD概念 Apache Spark的核心组件的基础是RDD。所谓的RDD&#xff0c;即弹性分布式数据集&#…

Linux 关闭防火墙命令(新手)

关闭防火墙 查看防火墙状态 systemctl status firewalld.service 临时关闭防火墙&#xff08;重启失效&#xff09; systemctl stop firewalld.service 永久关闭防火墙 systemctl disable firewalld.servicesudo systemctl enable firewalld&#xff0c;这种方式输入命令…

施耐德 Unity Pro PLC 编程软件介绍

Unity Pro 软件基本介绍 Unity Pro 是施耐德中大型 PLC 的编程软件&#xff08;<–> 对应西门子 Step7&#xff09; 支持的 PLC&#xff1a;施耐德中大型 PLC 中型 PLC&#xff1a;Premium、M340&#xff08;<–> 对应西门子 S7-300、S7-1200&#xff09;大型 PL…

【C++】探索C++中的类与对象(上)

​​ &#x1f331;博客主页&#xff1a;青竹雾色间. &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 ✨人生如寄&#xff0c;多忧何为 ✨ C是一种强大的编程语言&#xff0c;其面向对象的特性使得代码结构更加清晰、易于维护和扩展。在C中&#xff0c;类与…

Day83:服务攻防-开发组件安全JacksonFastJson各版本XStreamCVE环境复现

目录 J2EE-组件Jackson-本地demo&CVE 代码执行 (CVE-2020-8840) 代码执行 (CVE-2020-35728&#xff09; J2EE-组件FastJson-本地demo&CVE FastJson < 1.2.24 FastJson < 1.2.47 FastJson < 1.2.80 (利用条件比较苛刻) J2EE-组件XStream-靶场&CVE …

高度不同的流体瀑布css实现方法

商城商品列表 实现瀑布流展示&#xff0c;通过flex或grid实现会导致每行中的列高度一致&#xff0c;无法达到错落有致的感觉&#xff1b; 为此需要用到&#xff1a; CSS columns 属性 columns 属性是一个简写属性&#xff0c;用于设置列宽和列数。 CSS 语法 columns: column-wi…

字节新作:图像生成质量超越DiT

&#x1f31f;每日更新最新高质量论文&#xff0c;关注我&#xff0c;时刻关注最新大模型进展。&#x1f31f; &#x1f4cc; 元数据概览&#xff1a; 标题&#xff1a;Visual Autoregressive Modeling: Scalable Image Generation via Next-Scale Prediction作者&#xff1a…

算法设计与分析实验报告java实现(排序算法、三壶谜题、交替放置的碟子、带锁的门)

一、 实验目的 1&#xff0e;加深学生对算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 1、排序算法…

【随笔】Git 高级篇 -- 相对引用2(十三)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

4.4C++

1 #include <iostream> #include <cmath> using namespace std; class A{ private:int a;// 判断一个数是否为质数bool isP(int num) {if (num<2) return false;for (int i2;i<sqrt(num);i) {if (num % i 0) {return false;}}return true;} public:// 构造…

open-cd框架调试记录

源于论文Changer: Feature Interaction Is What You Need forChange Detection 源码位置&#xff1a;open-cd/README.md at main likyoo/open-cd (github.com) 同样是基于MMSegmentation框架的代码&#xff0c;不符合本人编程习惯所以一直也没有研究这东西&#xff0c;近期打…