【C++笔记】C++之类与对象(下)
【C++笔记】C++之类与对象(下)
- 1、再看构造函数
- 1.1、构造函数的初始化列表
- 1.2、C++支持单参数的构造函数的隐式类型转换
- 1.3、匿名对象
- 2、Static成员
- 2.1、为什么要有静态成员变量?
- 2.2、一个类的静态成员变量属于这个类的所有对象
- 2.3、静态成员函数
- 3、友元
- 3.1、友元函数
- 3.2、友元类
- 4、内部类
- 4.1、内部类与外部类是互相独立的
- 4.1、内部类默认是外部类的友元
1、再看构造函数
1.1、构造函数的初始化列表
为什么要引入初始化列表呢?
我们之前知道,在编译器自动生成的构造函数中,对于自定义类型会去调用其默认构造函数,但要是这个自定义类型没有可用的默认构造函数,就会出问题了,例如:

这时候先要解决这个问题,就要用到初始化列表了,因为在初始化列表中就可以对这个b进行定义。
初始化列表的语法如下图所示:

也就是初始化列表是在构造函数的大括号之前,以冒号开始以逗号分隔每个成员的值用括号定义。
初始化列表是每个成员定义的地方:
初始化列表是每个成员定义的地方,所以有了初始化列表之后,在就如构造函数的函数体之前就会去走初始化列表,然后再去走函数体。
我们通过调试就可以看出:


事实上,不管你写不写每个成员都要走初始化列表,这个我们可以通过为成员加上缺省值来验证,因为成员的缺省值就是给初始化列表用的:

可以看到,虽然我们并没有在初始化列表里面写上_month的定义,但是当走到_day的定义的时候,_month就已经定义成了我们所给的缺省值了。这就说明了_month其实也走了初始化列表。
其实在走完_year时,编译器是会自动跳到成员列表处去定义_month的:

正是因为不管怎样,每个成员都会走初始化列表,所以我们以后可以用初始化列表就尽量要用初始化列表。
初始化列表初始化的顺序和声明的顺序相同:
这个可以通过一个“反常”现象进行验证:

对于这个程序我们一般都会理解成,输出两个1,但是结果却不是这样。这其实就恰恰说明了初始化列表初始化的顺序是和声明的顺序是一样的,因为是a2先声明,所以初始化列表会先走a2的定义,但a1的只还是随机值。
所以就出现了以上的结果,只要我们改一下它们在初始化列表中的顺序,这程序就正常了:

所以为了避免出现各种问题,我们一般都要保证初始化列表初始化的顺序和声明的顺序一样。
而在吧编译器自动生成的构造函数中,其实是在初始化列表中对内置类型不作处理(假如没有给缺省参数),对于自定义类型则去调用其默认构造函数:

1.2、C++支持单参数的构造函数的隐式类型转换
C++之所以支持这个语法,主要还是能个好的应付自定义类型的一些场景,还是拿我们的栈来举例子,对于下面这个类,我们在定义对象的时候其实有两种写法:

这里的本质其实就是隐式类型转换,编译器会先用2去调用A的构造函数去生成一个临时对象,再用这个对象去拷贝构造a2。
但是编译器觉得先构造在拷贝构造太麻烦了,于是编译器就再次进行了优化,将拷贝构造省去,用2直接构造a2。
从下面的结果中我们也可以看到编译器只调用了构造函数:

1.3、匿名对象
在C语言中我们见过匿名结构体,在C++中也有一个匿名对象,即我们在定义对象的时候可以不给名字:

匿名对象的生命周期只在一行,我们可以通过加上析构函数来验证这一点:

我们会发现程序在运行下一行指令的时候,就会先去调用析构函数。
其实C++支持这个语法还是为了代码简便,例如我们现在有一个函数的参数是一个自定义类型,如果不支持匿名对象我们每次都要先定义一个有名对象再去传:

但是有了匿名对象之后,我们就可以直接传一个匿名对象了:

2、Static成员
2.1、为什么要有静态成员变量?
有时候我们可能会有这样的需求:统计一个类总共定义了对少个对象。
我们很容易会想到定义一个全局变量,然后再在构造函数和拷贝构造中让这个全局变量自加1:

但这个做法的缺点就在于全局变量的作用域太大了,很容易就会被修改,只要被外人一修改,这统计的就不对了。
所以为了解决这个问题,C++引入了静态成员变量:

2.2、一个类的静态成员变量属于这个类的所有对象
首先要说明的是静态成员变量并不在类里面,这一点可以通过计算类的大小来验证:

可以看到,A的大小为4,也就是说只计算了成员_a的大小,并没有计算N的大小。
实际上静态成员变量是存在于静态区的。
静态成员变量不能给缺省值,静态成员变量需要在类外边定义:

因为静态成员变量属于所有类,所以如果它是共有的,他就可以直接使用类作用限定符来访问,而其他成员变量就不可以:

2.3、静态成员函数
熟了静态成员变量,C++还有一个静态成员函数
静态成员函数没有this指针,所以静态成员函数不能访问非静态成员:

但是它可以自由的访问静态成员变量:

而且如上图所示,静态成员变量并没有this指针,所以在调用的时候也就不需要先有对象,直接是用来访问限定符突破类域即可。
3、友元
虽然在类里边我们可以随便访问成员变量而不受访问限定符的限制,但有些函数我们会发现将它写成成员函数会很奇怪,例如对日期我们需要使用运算符重载重载一个流插入运算符:

我们这好像写的没问题,但当我们去调用的时候却会发现问题了:

这里提示说未接收到参数,这是因为我们的顺序反了,我们知道非静态成员函数都会有一个隐藏的this指针,并且永远在第一位:

所以我们如果要调用,就需要这样:

这样就简直太奇怪了,而且使用起来也是真不习惯。
所以为了解决这个问题,我们就需要引入友元了。
3.1、友元函数
上面的这个问题主要是参数的顺序不对,所以我们可以考虑将其写成全局的,这样就可以随意安排参数的顺序了:

但是当我们在调用的时候却还是会出现问题:

因为这些成员都是私有的,我们不能够直接访问。
其实我们可以用一个简单的方法来解决,就是对应每一个成员都写一个共有的函数来返回对应成员的值:

但当成员有很多个的时候这种方法也不是很简便,所以我们就可以用到友元声明:

因为这里的友元函数仅仅只是个声明,所以写在任何地方都是可以的。
这样这个函数就可以直接访问这些成员了:

3.2、友元类
有时候我们需要在一个类里边定义另一个类的对象:

但是烦心的是我们并不能直接访问其成员,因为是私有的:

这时候我们就可以将Date类声明成A类的“友元类”,没错,友元不仅可以声明友元函数还可以声明友元类:

这样在Date类中就可以随意的访问A类中的成员了:

这其实和友元函数的作用是相同的。
但有一点需要注意:“友元”并不是相互的,就像这里只有Date类是A的友元类,但A并不是Date类的友元类,也就是说在A类中不可以直接访问Date类中的成员:

4、内部类
这就像结构体可以嵌套定义一样,类也可以嵌套定义:

4.1、内部类与外部类是互相独立的
“内部类”虽然名称叫做内部类,但事实上它本身却并不包含在外部类里,这一点我们可以通过计算类的大小来验证:

很明显这里A类的大小仅为4,如果要包含内部类的话至少也的是8才对。
但内部类受外部类的访问限定符的限制,比如内部类若是公有的我们就可以直接通过A的类作用限定符来定义对象:

如若是私有,就不能了:

4.1、内部类默认是外部类的友元
内部类的优势就是内部类默认是外部类的友元类,也就是说内部类可以直接访问到外部类的成员:

但上面也说过了,友元并不是相互的,所以外部类并不能直接访问内部类的成员:

相关文章:
【C++笔记】C++之类与对象(下)
【C笔记】C之类与对象(下) 1、再看构造函数1.1、构造函数的初始化列表1.2、C支持单参数的构造函数的隐式类型转换1.3、匿名对象 2、Static成员2.1、为什么要有静态成员变量?2.2、一个类的静态成员变量属于这个类的所有对象2.3、静态成员函数 3、友元3.1、…...
管理类联考——英语——实战篇——大作文——图表——动态图表——整体效果
动态图表模板 What is clearly presented in the above 图表类型 is that dramatic changes have taken place in 主题词1 from 年份1 to 年份2.During the period, there was a marked jump from 数字1 to 数字2 in 事物1,while that of 事物2 declined significantly from 数…...
threejs纹理加载三(视频加载)
threejs中除了能把图片作为纹理进行几何体贴图以外,还可以把视频作为纹理进行贴图设置。纹理的类型有很多,我们可以用不同的加载器来加载,而对于视频作为纹理,我们需要用到今天的主角:VideoTexture。我们先看效果&…...
VUE笔记(三)vue的语法
一、计算属性 1、计算属性的概念 计算属性是依赖于源数据(data或者属性中的数据),在元数据的基础上进行逻辑运算后得到的新的数据,计算属性要依赖于源数据,源数据数据变化计算属性也会变化 2、计算属性的语法 在vue2中使用computed这个选…...
探讨uniapp的路由与页面生命周期问题
1 首先我们引入页面路由 2 页面生命周期函数 onLoad() {console.log(页面加载)},onShow() {console.log(页面显示)},onReady(){console.log(页面初次显示)},onHide() {console.log(页面隐藏)},onUnload() {console.log(页面卸载)},onBackPress(){console.log(页面返回)}3 页面…...
咸鱼之王俱乐部网站开发
我的俱乐部 最新兑换码 *注意区分大小写,中间不能有空格! APP666 HAPPY666 QQ888 QQXY888 vip666 VIP666 XY888 app666 bdvip666 douyin666 douyin777 douyin888 happy666 huhushengwei888 taptap666 周活动 宝箱周 宝箱说明 1.木质宝箱开启1个…...
Electron+Vue3+TS 打包exe客户端
Electron Vue3 TS 实战 - 掘金 如果报错loaderContext.getOptions is not a function ts-loader版本不一致导致的问题。 解决方案:npm install ts-loader8.0.0 --save...
vue3范围选择组件封装
个人项目地址: SubTopH前端开发个人站 (自己开发的前端功能和UI组件,一些有趣的小功能,感兴趣的伙伴可以访问,欢迎提出更好的想法,私信沟通,网站属于静态页面) SubTopH前端开发个人站…...
能被整除的数(容斥原理)
思路: (1)需求:求对于1~n中至少能被p1~pm至少1个整除的数的个数,由于都是质数,彼此互质,不需要进行质因子分解,根据容斥原理, res n/p1 n/p2 ... n/pm - n /(p1p2) -…...
Modbus转Profinet网关与流量变送器兼容转ModbusTCP协议博图配置
首先,我们需要明确电磁流量计的通信协议是Modbus,而西门子1200PLC的通信协议是Profinet。这两种协议在功能和特性上存在一定的差异,因此需要使用兴达易控Modbus转Profinet网关设备进行转换。兴达易控的XD-MDPN100是Profinet转ModbusTCP的网关…...
HLS实现CORDIC算法计算正余弦并上板验证
硬件:ZYNQ7010 软件:MATLAB 2019b、Vivado 2017.4、HLS 2017.4、System Generator 2017.4 1、CORDIC算法计算正余弦 CORDIC算法详细分析网上有很多资料,它的原理是用一系列旋转去逼近目标角度,这一系列旋转的角度为 θ a r c t…...
高阶数据结构并查集
目录: 并查集的概念代码实现 LeetCode例题 并查集的概念 将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中反复遇到查询某一个元素属于那个集合的运算…...
WSL2连接不了外网怎么办?
某天忽然WLAN变成地球图标,上不了Internet,搞了半天网络适配器,仍然不行。回忆之前做过的操作,曾经运行过ZoogVPN,试着启动并连接,然后退出,WLAN神奇地恢复了连接,可以上Internet了。…...
【C/C++】探索内存对齐的奥秘与优势
目录 一,前言 二,什么是内存对齐? 三,内存对齐的原理 四,内存对齐的优势 五,如何实现内存对齐?(看这节就行) 1.使用 #pragma pack 来实现内存对齐的示例 七&#…...
leetcode分类刷题:滑动窗口(二、重复元素类型)
1、连续子数组、连续子串问题通常需要滑动窗口来求解,本篇文章对应的“二、重复元素类型”在此基础上对连续子数组、连续子串中重复元素个数、种类进行考察,此时,需要使用和维护哈希表进行左右指针的移动,因此这类题目对应的解法为…...
MySQL—buffer pool
一、buffer pool的介绍 Buffer pool是什么 一个内存区域,为了提⾼数据库的性能,数据库操作数据的时候,把硬盘上的数据加载到buffer pool,不直接和硬盘打交道,操作的是 buffer pool的数据,数据库的增删改查…...
《C和指针》笔记8: 枚举类型
枚举 (enumerated)类型就是指它的值为符号常量而不是字面值的类型,它们以下面这种形式声明: enum Jar_Type { CUP, PINT, QUART, HALF_GALLON, GALLON };这条语句声明了一个类型,称为Jar_Type。这种类型的变量按下列方式声明: e…...
Python爬虫框架之Selenium库入门:用Python实现网页自动化测试详解
概要 是否还在为网页测试而烦恼?是否还在为重复的点击、等待而劳累?试试强大的Selenium!让你的网页自动化测试变得轻松有趣! 一、Selenium库到底是什么? Selenium 是一个强大的自动化测试工具,它可以让你直…...
docker swarm 部署服务网络问题
docker swarm 服务部署问题 docker swarm 部署服务时可能会出现,启动服务特别慢的情况,甚至一个service 启动后,容器会长时间处于 preparing 状态,直到 状态切换成 running 状态后,才会启动下一个service。然后查询资…...
1.00001git源码clone后进行编译(带调试)
– 新建用户 useradd postgres passwd postgres – 用户加入sude组 先cd到/etc/sudoers目录下 由于sudoers文件为只读权限,所以需要添加写入权限,chmod uw sudoers vim sudoers 找到root ALL (ALL) ALL这一行,在下一行加入username ALL (A…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
