类和对象plus版
一.类的定义
1.1类定义的格式
图中class为关键字,Stack为类的名字,用{}框住类的主体,类定义完后;不能省略。
为了区分成员变量,一般习惯在成员变量前面或后面加一个特殊标识,_或者m_
1.2访问限定符
c++采用一种封装的方式,用类和对象的属性与方法结合在一起,让对象更加完善,通过访问权限选择性的将其接口提供给外部使用。
public修饰的成员在类外可以直接访问使用,private和protected修饰的成员在类外不能直接使用。
1.3类域
类定义了一个新的作用域,类的所有成员都在作用域中,在类体外定义成员时要用::操作符来指明成员。
二.实例化
类就像一个模型图纸一样,实例化之后可以实现许多的功能,但是在实例化之前,他是没有任何功能的,并且也不会占用实际的空间,只有当实例化出对象后,才能进行物理存储。
2.1对象大小
类实例化出的没一个成员都有独立的数据空间,那么类中的函数是否能进行储存呢?首先函数在编译之后是一段指令,对象无法进行存储。所以函数会以指针地址的方式,通过汇编指令call地址,找到函数的地址进行使用。
打个比方,类里面的成员变量每实例化一份就会开辟一份的空间,而类成员函数则会以一份公共的地址,放在一个代码公共区内。
三.this指针
在一个类中,若有多份成员函数,c++是如何找到访问对象的呢?
这里存在一个this指针,this指针在编译器编译后,会默认出现在第一个位置,增加一个当前类型的指针,类的成员访问成员变量,本质都是通过this指针来使用的。c++规定不能在形参和实参位置写this指针(编译器编译时会处理),但可以在函数体内使用this指针。
我们来看一串代码
它的编译结果是什么?
答案是正确通过!
p为空指针去访问类中的print函数,虽然是空指针,但是我们并没有拿去访问实体,所以不会出错。
若是这样去访问实体a所以就会运行崩溃
3.2this指针存在哪个区域内
常量区是用来存放一些字符类字符串类的全局变量。堆区是用来存放malloc手动开辟的空间变量的存储区域。静态区内存放的是static修饰的变量,以及全局变量。栈区是存放函数的形参实参的空间,以及函数内的变量。
很明显这里的this指针应当存放在栈区。
四.类的默认成员函数
4.1概念
默认成员函数就是用户没有显示实现,编译器会自动生成的成员函数称为默认成员函数。一个类,我们不写的情况下会默认生成6个成员函数。分别为,构造函数负责完成初始化工作,析构函数负责完成清理工作,拷贝构造是使用同类对象初始化创建对象,赋值重载只要是把一个对象赋值给另一个对象,取地址重载主要是将普通对象和const对象取地址。
4.2构造函数
构造函数是特殊的成员函数,虽然他的名字叫构造,但并不是以开空间创建对象为目的,而是对象实例化时初始化对象。构造函数的本质是为了替代以前stack类中写Init的功能,构造函数自动调用完美解决了此类问题。
4.2.2构造函数的特点以及实现
函数名与类名相同(在类中单独初始化,且名字为类名)。
无返回值(不需要给任何的类型,c++规定如此)。
对象实例化时会自动调用函数。如下图,d1会自动初始化三个值为1。
构造函数可以重载,我们可以根据自身需要设置变量的值,以及是否需要缺省参数。
若我们不写,编译器会默认初始化生成默认构造函数,若成员变量为基本类型(char int double 指针等)那么编译器就会报错。若成员变量为自定义类型(先前已经在类中定义过的类型)就可以正常进行初始化。
无参构造函数,全缺省构造函数,默认生成的构造函数,都叫做默认构造函数(不传实参就可以调用),这三个函数有且只能存在一个,不能同时存在。
4.2.3构造函数实现法2
除了用函数体内赋值的方法,构造函数初始化还有一种方法就是初始化列表,初始化列表从一个冒号开始,用逗号分隔数据成员列表,每个成员变量后面跟一个放在括号中的初始值或表达式。(在{}和()中只能初始化一次)
当面对引用成员,const成员变量,没有默认构造的类类型变量,必须在:下进行定义。因为这些变量已经在主函数中定义过了,无法在构造函数中重新定义,所以只需要在:下定义即可使用。
4.2.4成员变量初始化逻辑
显示在初始化列表的成员变量就按这个值进行初始化。未显示在初始化列表的成员,如果有缺省值或者就按缺省值初始化,若没有缺省值,内置类型成员可能会初始化为随机值,自定义类型成员若有对应的构造函数那么就可以调用若没有则会报错。引用,const,没有默认构造函数的成员必须在初始化列表进行初始化。成员变量会根据声明的顺序进行初始化,所以尽量按照声明顺序进行定义。
4.3析构函数
析构函数与构造函数相反,析构函数是完成对对象本身的销毁,例如我们需要在函数内申请空间,当栈帧销毁时要先做清理资源使得资源释放。
4.3.2析构函数的特点
要在析构函数前加上~。(析构函数要与类同名)
参数无返回值,且一个类只能有一个析构函数,若未显示定义,系统会自动生成。
对象生命周期结束时,系统会自动调用析构函数。
跟构造函数类似,若我们不写编译器自动生成的析构函数对内置类型不做处理,自定类型成员则调用他们的析构函数。
若类中没有资源申请,析构函数可以不写,直接使用编译器生成的默认析构函数。但是当有资源申请时,一定要自己写析构函数,否则就会造成资源泄露。
4.3.3构造函数和析构函数的顺序
构造函数遵循,先全局变量,再局部变量,然后是局部静态变量。全局变量指在main主函数外的的变量,静态变量指static修饰的变量,而局部变量就指主函数内的变量。遵循从上到下的顺序进行构造。
析构时,遵循先局部再全局的思路,先析构局部的简单变量,再析构静态变量,最后是全局变量
4.4拷贝构造函数
类似于键盘的复制粘贴,用于复制类类型的函数。拷贝构造需要接受拷贝的必须是未存在的对象,而拷贝的必须是存在的对象。
4.4.1拷贝构造函数特点
1.拷贝构造函数是构造函数的一个重载。将函数内部的值copy到拷贝构造函数中。
2.拷贝构造函数的参数只有一个且必须是类类型对象的引用(可以有其他参数,但必须是缺省参数),使用传值方式编译器会报错,因为会在语言逻辑上引发无穷递归调用。
所以在拷贝时必须使用引用直接指向原先的类。
通过加上Const来防止拷贝的值被轻易修改。
若没有使用&符号,每当我们需要拷贝时,就要重新开辟一块空间,调用一次构造函数,此时通过拷贝函数将其copy进来,但是当我们调用拷贝函数时又会重新开辟一块新的空间,反复上述步骤。
3.若未显示定义拷贝构造,那么系统会调用默认的拷贝构造。这里的拷贝构造是浅拷贝,若变量为int,char这些类型的变量,拷贝时会单独开辟一块空间储存他们的值。若变量为malloc出的一块空间,或者指针文件类的指向型,浅拷贝后,还会指向原先的地址。若是这样一旦函数析构,或者变量改变,就会影响到拷贝的值。所以我们需要在拷贝函数上重新单独为其开辟一块新的空间储存。
五.赋值运算符重载
5.1运算符重载
当运算符被用于类类型的对象时,编译器无法直接识别运算符定义,所以我们需要重新进行运算符定义。我们用operator和后面要定义的运算符共同构成,他相当于一个函数,拥有返回类型和参数列表以及函数体。重载的运算符函数的参数个数要与运算对象个数一样多,并且按照顺序进行排列。若重载运算函数是成员函数,则它的第一个运算对象默认传给隐形的this指针,所以运算符重载作为成员函数后,参数少一个。运算符重载后,其优先级和结合性与对应的内置类型运算符保持一致。当然也并不是所有的运算符都能重载,像.* :: sizeof ?: .不能进行重载
如图其中的.*是调用成员函数指针的符号。
一个类需要重载哪些运算符是看哪些运算符重载之后有意义,比如日期减日期可以得到天数,但日期加日期就无意义。
重载运算前置++和后置++时,重载名都是++,无法区分,所以c++规定,后置++重载时,增加一个int形参,跟前置++构成函数重载用于区分。
5.2赋值运算符重载
赋值运算符重载是一个默认成员函数,用于完成两个已经存在的对象直接拷贝赋值,这里需要跟拷贝构造进行区分,拷贝构造是一个对象拷贝初始化给另一个要创建的对象。
5.2.1特点
1.赋值运算符应当写成const当前类类型的引用,否则传参会有拷贝降低效率。
2.没有显示实现时,编译器会自动生成一个默认赋值运算符重载,默认赋值运算符重载为浅拷贝,对于动态开辟空间的变量会同时使用同一块空间,会导致错误发生。也就是说,当成员内有多个对象享用同一块空间时,需要自行手动实现。
3.手动实现时,需要先释放当前对象已有的资源,以避免内存泄露,对于(int,double)这类型的直接进行赋值,对于指针这类的需要重新开辟空间,进行深拷贝。最后返回当前对象的引用。
4.注意当出现a=a的情况,直接释放资源会导致错误,所以开头先判断两者地址是否重叠再进行拷贝。
代码参考
5.3日期实现
5.3.1 Date.h
其中对于自身有改变的函数需要传递引用值,对于this指针不存在改变的要在函数后添加const修饰。
5.3.2 Date.cpp
对于代码相似的函数实现尽可能的使用函数调用,这样可以减少代码量并且使得程序更加可观。
ostream&和&istream是c++库中定义的一个流输入输出重载的函数名。我们在类中定义友元函数,因为函数调用时是按照严格的左右位置调用的。
六.类型转换
当我们使用=来赋值类类型时,会存在一个隐式的类型转换,开辟一块空间将其进行拷贝函数赋值。
若是遇到引用符号时,因为临时对象具有常性,所以在传值时,左值必须使用const将变量转变为常性。若等号传参时有多个变量则用{}来包含值,若是有多组则以这样的形式传值{{},{}}。若是自定义类型转换则需要相应的构造来支持。
七.static成员
7.1static成员特点
用static修饰的成员变量称之为静态成员变量,静态成员变量一定要在类的外部进行初始化。静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。用静态成员修饰的函数没有this指针,意味着函数内部不能访问非静态的成员,只能访问静态成员。而非静态的成员函数可以访问任意的静态成员变量和静态成员函数,只需要进行突破类域。突破类域有两种方法,类名::静态成员或者对象.静态成员。静态成员不走初始化列表,因为他不属于某个对象,也不能进行声明位置的初始化,但需要在声明处进行声明。
八.内部类
内部类就是在一个类里面再封装一个类,当这两个类之间有着紧密联系或者a类是为b类专门实现的时候可以使用(内部类默认是外部类的友元类)。内部类是一个独立的类,与定义在全局相比,它只受外部类类域限制和访问限定符限制,所以外部类的对象中不包含内部类。
九.匿名对象
用类型(实参)定义出来的对象叫做匿名对象,匿名对象的生命周期只在当前一行。
若我们想延长匿名对象的生命周期,可以使用const a& b = A()的方法来延长生命。
匿名对象的用法主要服务于,当函数调用时给类类型给缺省值,无法直接给出时。
十.对象拷贝时的编译器优化
编译器为了提高程序的运行效率,在不影响正确性的情况下会尽可能减少一些传参过程中可以省略的拷贝。
在不优化的版本下,f2中的aa传值过程中,会预先开辟一块空间接收return aa的值,再将值进行一次拷贝构造给回aa2中。在vs2019的debug版本下,则会省略掉中间值的拷贝构造,而是直接将return的返回值拷贝构造给aa2。而在release版本下,则会更加的激进,return返回的aa直接就是aa2的引用返回值,直接省略了空间的开辟。
相关文章:

类和对象plus版
一.类的定义 1.1类定义的格式 图中class为关键字,Stack为类的名字,用{}框住类的主体,类定义完后;不能省略。 为了区分成员变量,一般习惯在成员变量前面或后面加一个特殊标识,_或者m_ 1.2访问限定符 c采用…...

shell练习
开篇小贴士:为创建的sh(当然可以是任何一个文件)文件添加开头的注释 1、进入到家目录,然后通过 ls -a 查看全部文件 2、找到并编辑一个名为 .vimrc (Vim编辑器的核心配置文件)的配置文件,下图…...

ApiChain 从迭代到项目 接口调试到文档生成单元测试一体化工具
项目地址:ApiChain 项目主页 ApiChain 简介 ApiChain 是一款类似 PostMan 的接口网络请求与文档生成软件,与 PostMan 不同的是,它基于 项目和迭代两个视角管理我们的接口文档,前端和测试更关注版本迭代中发生变更的接口编写代码…...

Vercel 设置自动部署 GitHub 项目
Vercel 设置自动部署 GitHub 项目 问题背景 最近 Vercel 调整了其部署政策,免费版用户无法继续使用自动部署功能,除非升级到 Pro 计划。但是,我们可以通过配置 Deploy Hooks 来实现同样的自动部署效果。 解决方案 通过设置 Vercel 的 Dep…...

SQL进阶:如何跳过多个NULL值取第一个非NULL值?
NULL 一、问题描述二、ORACLE<一>、last_value () over ()<二>、lag () over()<三>、相关子查询 三、MYSQL<一>、全局变量<二>、coalesce() lag() over()<三>、相关子查询<四>、 recursive<五>、lag() over() min() over() …...

laravel 5.5 增加宏指令 joinSub, 省去->toSql() 和 addBinding($bindings);
laravel 5.5 增加宏指令 joinSub, 省去->toSql() 和 addBinding($bindings); 1. 在laravel5使用join 子查询时 $sub_query DB::table(table1)->select([table1.id, cate_id])->join(table2, table1.id, , table2.id)->where(table1.cate_id, 2)->orderBy(tabl…...

远程控制软件:探究云计算和人工智能的融合
在数字化时代,远程控制工具已成为我们工作与生活的重要部分。用户能够通过网络远程操作和管理另一台计算机,极大地提升了工作效率和便捷性。随着人工智能(AI)和云计算技术的飞速发展,远程控制工具也迎来了新的发展机遇…...

网络协议之DNS
一、DNS概述 域名系统(Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用TCP和UDP端口53,通过递归查询请求的方式来…...

.net6 使用 FreeSpire.XLS 实现 excel 转 pdf - docker 部署
FreeSpire.XLS && Aspose.Cells包都可以实现。实现过程中发现如下问题: 本地测试通过, docker部署服务器后报错: The type initializer for Spire.Xls.Core.Spreadsheet.XlsPageSetupBase threw an exception. 由于缺少依赖…...

QML学习 —— 28、3种等待指示控件(附源码)
效果如下 说明 BusyIndicator应用于指示在加载内容或UI被阻止等待资源可用时的活动。BusyIndicator类似于一个不确定的ProgressBar。两者都可以用来指示背景活动。主要区别在于视觉效果,ProgressBar还可以显示具体的进度(当可以确定时)。由于视觉差异,繁忙指示器和不确定的…...

flutter 专题十一 Fair原理篇Fair逻辑动态化架构设计与实现
数据逻辑处理布局中的逻辑处理Flutter类型数据处理 一、数据逻辑处理 我们接触的每一个Flutter界面,大多由布局和逻辑相关的代码组成。如Flutter初始工程的Counting Demo的代码: class _MyHomePageState extends State<MyHomePage> {// 变量 in…...

利用开源图床的技巧与实践
随着互联网的普及,图片的使用变得越来越广泛。无论是个人博客、社交媒体还是企业网站,都离不开图片的呈现。而图床作为图片存储和管理的工具,可以帮助开发者和内容创作者高效地管理图片资源。本文将探讨如何利用开源图床,并提供相…...

C++数据结构与算法
C数据结构与算法 1.顺序表代码模版 C顺序表模版 #include <iostream> using namespace std; // 可以根据需要灵活变更类型 #define EleType intstruct SeqList {EleType* elements;int size;int capacity; };// Init a SeqList void InitList(SeqList* list, int capa…...

Paddle Inference部署推理(三)
三:Paddle Inference推理 导出模型 Paddle Inference支持使用飞桨静态图模型进行推理,您可以通过以下两种方式获取静态图模型: (1)飞桨框架导出推理模型 飞桨框架在训练模型过程中,会在本地存储最终训练…...

python(四)os模块、sys模块
一、os模块 os 模块提供了很多程序与操作系统直接交互的功能 名称描述示例os.getcwd()得到当前工作目录,即当前Python脚本工作的目录路径‘D:\python’os.listdir()返回指定目录下的所有文件和目录名>>> os.listdir()os.remove()函数用来删除一个文件>…...

Oracle 数据库 IDENTITY 列
IDENTITY列是Oracle数据库12c推出的新特性。之所以叫IDENTITY列,是由于其支持ANSI SQL 关键字 IDENTITY,其内部实现还是使用SEQUENCE。 不过推出这个新语法也是应该的,毕竟MyQL已经有 AUTO_INCREMENT列,而SQL Server也已经有IDENT…...

【前端】js vue 屏蔽BackSpace键删除键导致页面后退的方法
【前端】js vue 屏蔽BackSpace键删除键导致页面后退的方法 方法一:通过全局事件监听阻止 Backspace 导致页面后退 在 main.js 或组件的 mounted 中添加以下代码: //【前端】js vue 屏蔽BackSpace键删除键导致页面后退的方法 document.addEventListener…...

深入解密 K 均值聚类:从理论基础到 Python 实践
1. 引言 在机器学习领域,聚类是一种无监督学习的技术,用于将数据集分组成若干个类别,使得同组数据之间具有更高的相似性。这种技术在各个领域都有广泛的应用,比如客户细分、图像压缩和市场分析等。聚类的目标是使得同类样本之间的…...

ArcGIS应用指南:ArcGIS制作局部放大地图
在地理信息系统(GIS)中,制作详细且美观的地图是一项重要的技能。地图制作不仅仅是简单地将地理数据可视化,还需要考虑地图的可读性和美观性。局部放大图是一种常见的地图设计技巧,用于展示特定区域的详细信息ÿ…...

非root用户安装CUDA
1.使用nvidia-smi查看当前驱动支持的最高CUDA版本: 表示当前驱动最多支持cuda12.1 2.进入cuda安装界面,https://developer.nvidia.com/cuda-toolkit-archive,选择想要安装的版本,例如想要安装CUDA11.4: 如果需要查看ub…...

单点修改,区间求和或区间询问最值(线段树)
【题目描述】 给定一个长度为n的非负整数序列,接下来有m次操作,操作共有3种:一是修改序列中某个元素的大小,二是求某个区间的所有元素的和,三是询问某个区间的最大值。整数序列下标从1开始。n<10^5, m<10^5。 …...

线性代数空间理解
学习线性代数已经很久,但是在使用过程中仍然还是不明所以,比如不知道特征向量和特征值的含义、矩阵的相乘是什么意思、如何理解矩阵的秩……。随着遇到的次数越来越多,因此我决定需要对线性代数的本质做一次深刻的探讨了。 本次主要是参考了3…...

Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序
在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序 IntelliJ IDEA 是一个用 Java 编写的集成开发环境 (IDE)。它用于开发计算机软件。此 IDE 由 Jetbrains 开发,提供 Apache 2 许可社区版和商业版。它是一种智能的上下文感知 IDE,可用于在各种应用程序…...

C51相关实验
C51相关实验 LED //功能:1.让开发板的LED全亮,2,点亮某一个LED,3.让LED3以5Hz的频率闪动#include "reg52.h"#define LED P2 sbit led1 LED^1;void main(void) {LED 0xff;//LED全灭led1 0;while(1)//保持应用程序不退出{} }LED 输出端是高…...

docker离线安装linux部分问题整理
0:离线安装docker过程命令 echo $PATH tar -zxvf docker-26.1.4.tgz chmod 755 -R docker cp docker/* /usr/bin/ root 权限 vim /etc/systemd/system/docker.service --------- [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.do…...

ISUP协议视频平台EasyCVR萤石设备视频接入平台银行营业网点安全防范系统解决方案
在金融行业,银行营业厅的安全保卫工作至关重要,它不仅关系到客户资金的安全,也关系到整个银行的信誉和运营效率。随着科技的发展,传统的安全防护措施已经无法满足现代银行对于高效、智能化安全管理的需求。 EasyCVR视频汇聚平台以…...

递推概念和例题
一、什么是递推 递推算法以初始值为基础,用相同的运算规律,逐次重复运算,直至求出问题的解,它的本质是按照固定的规律逐步推出(计算出)下一步的结果 这种从“起点”重复相同的的方法直至到达问题的解&…...

开发工具 - VSCode 快捷键
以下是一些常用的 VS Code 快捷键(Windows、macOS 和 Linux 均适用,略有不同): 常用快捷键 功能Windows/LinuxmacOS打开命令面板Ctrl Shift P 或 F1Cmd Shift P打开文件Ctrl OCmd O保存文件Ctrl SCmd S全部保存Ctrl K,…...

数据库的联合查询
数据库的联合查询 简介为什么要使⽤联合查询多表联合查询时MYSQL内部是如何进⾏计算的构造练习案例数据案例:⼀个完整的联合查询的过程 内连接语法⽰例 外连接语法 ⽰例⾃连接应⽤场景示例表连接练习 ⼦查询语法单⾏⼦查询多⾏⼦查询多列⼦查询在from⼦句中使⽤⼦查…...

【人工智能】基于PyTorch的深度强化学习入门:从DQN到PPO的实现与解析
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 深度强化学习(Deep Reinforcement Learning)是一种结合深度学习和强化学习的技术,适用于解决复杂的决策问题。深度Q网络(DQN)和近端策略优化(PPO)是其中两种经典的算法,被广泛应用于游戏、机器人控…...