类和对象——相关的零碎知识
前提提示:
其实C++中的类和对象,最重要的是6个默认函数,如有忘记,请移步到:类和对象。本章是对于一些细节知识的补充和拓展。
1. 隐示类型转换
在运算时,运算符左右两边的操作数的类型不同,编译器是会按照类型转换的要求,将两个操作数的类型转换为一样,然后就行运算。
1.1 内置类型的隐示类型转换
我们的内置类型,他们之间出现类型不一致的情况时,是有一套类型转换的规则的,但是还有自定义类型,内置类型和自定义类型之间是如何转化?
答:这个其实和我们的前面将的构造函数有关了,其实在类型转换的时候,我们可以很容易的发现,被类型转化的变量其实没有改变,但是确确实实有实现了运算,就是因为隐示类型转换的时候,产生了临时变量,临时变量存储着变量类型转换之后的结果。
#include<iostream>
using namespace std;int main()
{double b = 1.223;int a = b;cout << a << " " << b << endl;return 0;
}

程序的执行逻辑:

这串代码实际上就是可以反映出,在隐示类型转换时,产生了临时变量。如果不产生临时变量,那么输出的结果是:1 1,但输出的结果是1 1.223 ,就说明产生了临时变量。
1.2 自定义类型的隐示类型转换
解释:这里的自定义类型的隐示类型转换,是指内置类型想自定义类型转换,自定义类型是无法想内置类型转换的。同时不同的自定义类型之间也是不能互相类型转换的。
#include<iostream>
using namespace std;class A
{
public://构造函数A(int a): x(a),y(a){cout << "A(int a)" << endl;};void operator=(A&a){x = a.x;y = a.y;cout << "void operator=(A&a)" << endl;}private:int x;int y;
};int main()
{int a = 6;A tmp = a;return 0;
}
上述程序中的两个变量 a和tmp的类型不相同,那他们是怎么进行隐示类型转换的呢?这个就需要和之前的初始化列表联系起来了,因为这个转换需要使用到类的6个默认函数中的连续构造函数和拷贝构造,程序的执行逻辑如下。

程序输出的结果:

为什么上面讲的是先连续构造然后拷贝构造,为什么程序在执行的时候只进行了普通的构造?这是因为编译器的优化。编译器将连续构造+拷贝构造优化为直接构造,这样更加的节省空间和时间。但是我们也发现其实这样的隐示类型转换时十分依赖于构造函数的书写的。
当将构造函数修改为如下:
class A
{
public://构造函数A(int a=0,int b=5): x(b),y(b){cout << "A(int a)" << endl;cout << x << " " << y << endl;};A(const A&a){x = a.x;y = a.y;cout << "A(A&a)" << endl;}private:int x;int y;
};int main()
{int a = 6;A tmp = a;return 0;
}
输出的结果:

当构造函数与需要类型转换的内置类型变量无关时。上面的例子就是,虽然传入了a但是没有使用a对类中的成员变量初始化,而是使用b的缺省值进行初始化,这时虽然将int类型转换为A类型但是是与a无关的。
进阶:
上面在演示程序逻辑时,a变量作为实参,去匹配构造函数的参数列表时,并没有说参数的数量,实际上a不只是能匹配一个参数的构造函数,还可以匹配多个参数的构造函数(其他第一个参数,其他的参数都需要有缺省值才行)。其实自定义的类型的隐示类型转换就是通过直接构造函数完成的,那能不能传入多个不同的类型转化为自定义类型?
class A
{
public://构造函数A(int a,int b): x(a),y(b){cout << "A(int a)" << endl;cout << x << " " << y << endl;};
private:int x;int y;
};
int main()
{int a = 6;int b = 7;A tmp = {a,b};return 0;
}
程序运行的结果:

结论:
1.并不是只能一个类型进行隐示类型转换,多个类型也是可以隐示类型转换的,多个类型隐示类型转换的步骤和上面一样,只是这次向构造函数的传参不是一个。
2.构造函数不仅可以构造和初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。
1.2.1 explicit关键字
上面讲了自定义类型的隐示类型转换是通过构造函数来完成隐示类型转换,当我们不允许隐示类型转换时,会在构造函数前面加上explicit这个关键字。
class A
{
public://构造函数explicit A(int a,int b): x(a),y(b){cout << "A(int a)" << endl;cout << x << " " << y << endl;};
private:int x;int y;
};
int main()
{int a = 6;int b = 7;A tmp = {a,b};return 0;
}
这段程序是报错的,原因就是在构造函数前面加上了explicit关键字,还进行了隐示类型转换。
2. Static关键字
2.1 Static类成员
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量。
特性:
- 静态成员为所有的类型共有,放在静态区。
- 静态成员变量只创建一次,静态成员变量必须在类的外面定义,定义是不加static关键字。
- 静态成员变量可以使用:类名:静态成员或者对象.静态成员访问。
- 静态成员变量也是类型的成员,是受到public,private和protect的保护的。
代码演示
class A
{
public://构造函数A(int a,int b): x(a),y(b){cout << "A(int a)" << endl;cout << x << " " << y << endl;};
private:int x;int y;static int c;
};
int A:: c = 5;
int main()
{int a = 6;int b = 7;A tmp = {a,b};return 0;
}
2.2 Static修饰成员函数
用static修饰的成员函数,称之为静态成员函数
特性:
- 静态成员函数被static修饰,没有this指针,只能访问静态成员变量。
- 静态成员函数是不在成员函数存储的地方的。
代码演示:
class A
{
public://构造函数A(int a, int b): x(a),y(b){};static int get(){return c;}
private:int x;int y;//静态成员变量的声明static int c;
};
//静态成员变量的定义
int A:: c = 5;
int main()
{int a = 6;int b = 7;A tmp = {a,b};cout << tmp.get() << endl;;return 0;
}
输出的结果:

3. const修饰
const放在成员函数的参数括号的后面,这个const是用来修饰*this指针的,是为了不让通过this指针修改类中的成员变量。如:const *this
代码演示:
class A
{
public://构造函数A(int a, int b): x(a),y(b){cout << "x=" << x <<" " << "y=" << y << endl;};//const修饰的成员函数void get()const{//这个是不能修改类中的成员变量的x = 4;y = 5;}
private:int x;int y;static int c;
};
代码结果:
这个代码是报错的

4. 友元类和友元函数
4.1 友元函数
友元函数可以直接访问类的私有成员变量,它的定义是在类的外面的普通函数,不属于任何类,但是需要在类中声明,声明时需要加friend关键字。
特性:
- 友元函数可以访问私有和保护成员变量
- 友元函数没有this指针,所有不能const修饰
- 友元函数可以在类的任何位置进行声明,不受访问限定符的限制
- 一个函数可以是多个类的友元函数
- 友元函数和普通函数的调用是一样的
代码演示:
#include<iostream>
using namespace std;
class A
{
public://构造函数A(int a, int b): x(a),y(b){cout << "x=" << x <<" " << "y=" << y << endl;};friend void get(int& n, int& m, const A& wa);
private:int x;int y;static int c;
};
int A:: c = 5;void get(int& n,int& m,const A& wa)
{n = wa.x;m = wa.y;}
int main()
{int a = 6;int b = 7;A tmp = {a,b};int n, m;get(n, m, tmp);cout << "n=" << n << " "<<"m=" << m << endl;return 0;
}
代码运行结果:

**结论:**当我们在类的外部定义的普通函数需要使用类中的成员变量时,就可以在该类中声明友元函数,这个该普通函数就可以访问类中的成员变量。
4.2 友元类
有一个类是另一个类的友元类,该类型中的成员函数都另一个类的友元函数,该类的成员函数都可以访问另一个类的非公有成员变量。
特性:
- 友元关系是单向的,比如:A是B的友元类,A是可以访问B中的成员变量,但是B不是A的友元,B是不可以访问A中的成员变量的。
- 友元关系是不能传递的,A是B的友元,B是C的友元,这并不意味这A是C的友元。
- 友元关系是不能继承的。
代码演示:
#include<iostream>
using namespace std;class A
{
public://构造函数A(int a, int b): x(a),y(b){cout << "x=" << x <<" " << "y=" << y << endl;};friend class B;
private:int x;int y;static int c;
};
class B
{
public:int get(const A& a){return a.x;}};
int A:: c = 5;
int main()
{int a = 6;int b = 7;A tmp = {a,b};B tm;int n = tm.get(tmp);cout << n << endl;return 0;
}
代码运行的结果:

5. 内部类
概念:一个类定义在另一个类的内部,就称该类是另一个类的内部类。
特性:
- 内部类和外部类是平等的,内部类虽然在外部类中定义,但是内部类是不属于外部类的,sizeof(外部类)是不会算上内部类的。
- 内部类是外部类的友元类,他们之间遵循友元关系的定义和用法,但是外部类不是内部类的友元。
- 内部类可以定义在外部类的任何位置。
- 内部类是可以直接访问外部类中的static成员变量的,不需要加上对象名/类名。
- 虽然说内部类和外部类是平等的,但是内部类需要定义是需要通过外部类的。
代码演示:
#include<iostream>
using namespace std;class A
{
public://构造函数A(int a, int b): x(a),y(b){cout << "x=" << x <<" " << "y=" << y << " " << "c=" << c << endl;};class B{public:int get(A& a){return c;}};
private:int x;int y;static int c;
};int A:: c = 5;int main()
{int a = 6;int b = 7;A tmp = {a,b};A::B p;cout << p.get(tmp) << endl;return 0;
}
代码的运行结果:

6. 匿名对象
特性
- 匿名对象是不需要取名字的
- 匿名对象的生命周期只有它定义的这一行
代码演示:
#include<iostream>
using namespace std;
class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
int main()
{A();return 0;
}
程序运行的结果:

7. 拷贝时编译器的一些优化
- 连续构造+拷贝构造直接优化为直接构造。
- 连续拷贝构造+拷贝构造直接优化为拷贝构造。
- 连续拷贝+赋值重载是没有办法进行优化的。
相关文章:
类和对象——相关的零碎知识
前提提示: 其实C中的类和对象,最重要的是6个默认函数,如有忘记,请移步到:类和对象。本章是对于一些细节知识的补充和拓展。 1. 隐示类型转换 在运算时,运算符左右两边的操作数的类型不同,编译器…...
【hadoop大数据集群 1】
hadoop大数据集群 1 文章目录 hadoop大数据集群 1一、环境配置1.安装虚拟机2.换源3.安装工具4.安装JDK5.安装Hadoop 一、环境配置 折腾了一下午/(ㄒoㄒ)/~~ 1.安装虚拟机 参考视频:https://www.bilibili.com/video/BV18y4y1G7JA?p17&vd_sourcee15e83ac6b22a…...
TQSDRPI开发板教程:实现PL端的UDP回环与GPSDO
本教程将完成一个全面的UDP运行流程与GPSDO测试,从下载项目的源代码开始,通过编译过程,最终将项目部署到目标板卡上运行演示。此外,我们还介绍如何修改板卡的IP地址,以便更好地适应您的网络环境或项目需求。 首先从Gi…...
array.some() ==> 查找数组list中,是否有包含与当前currKey的值不一样的misId
需求: const list [ {misId: e, name: 小白}, {misId: e, name: 小白白}, {misId: r, name: 小王}, {misId: r, name: 小小王} ] let currKey r 查找数组list中,是否有包含与当前currKey的值不一样的misId 解决: 要查找数组lis…...
最简单的typora+gitee+picgo配置图床
typoragiteepicgo图床 你是否因为管理图片而感到头大?是时候了解一下 Typora、Gitee 和 PicGo 这个超级三剑客了,它们可以帮你轻松打造自己的图床,让你的博客图片管理变得简单又有趣。让我们开始这场神奇的图床之旅吧! Typora …...
【黄啊码】GPT的相关名词解释
GPT是一种基于互联网的、可用数据来训练的、文本生成的深度学习模型 GPT的核心技术是变换器(Transformer),这是一种神经网络结构,可以有效地处理序列数据,比如文本、语音、图像等。GPT使用了大量的预训练数据&#…...
git stash 命令详解
git stash 描述 git stash 命令用于将当前工作目录中的未提交更改(包括暂存区和工作区的更改)保存到一个栈中,并恢复工作目录到干净的 HEAD 状态。这样您可以在不提交当前更改的情况下,切换到其他分支或进行其他操作。后续可以通…...
txt格式单词导入有道词典生词本 (java代码方式)
txt格式单词导入有道词典生词本 (java代码方式) 首先要求txt文档里单词的格式,大概需要像这种: 每行是一个单词,格式为:英文单词空格词性单词意思。 注意 导出单词本的名字就是你 txt 文件的名字 我这里是 公共英语三级 单词本 …...
轨迹优化 | 基于ESDF的共轭梯度优化算法(附ROS C++/Python仿真)
目录 0 专栏介绍1 数值优化:共轭梯度法2 基于共轭梯度法的轨迹优化2.1 障碍约束函数2.2 曲率约束函数2.3 平滑约束函数 3 算法仿真3.1 ROS C实现3.2 Python实现 0 专栏介绍 🔥课程设计、毕业设计、创新竞赛、学术研究必备!本专栏涉及更高阶的…...
深入浅出WebRTC—ALR
ALR(Application Limited Region)指的是网络传输过程中,由于应用层的限制(而非网络拥塞)导致带宽未被充分利用的情况。在这种情况下,应用层可能因为处理能力、手动配置或其他因素无法充分利用可用带宽&…...
BSV区块链技术现实应用原理解析
BSV区块链以其卓越的可扩展性、坚如磐石的安全性、极低的交易成本等特性,成为满足企业当下需求并为企业未来成功奠基铺路的理想技术。 BSV协会近期发布了一个题为《驾驭数字化转型:在自动化世界中建立信任——区块链在数据保护和交易优化中的角色》的报…...
七大基于比较的排序算法
目录 一、基于比较的排序算法概述 1. 插入排序(Insertion Sort) 2. 选择排序(Selection Sort) 3. 冒泡排序(Bubble Sort) 4. 归并排序(Merge Sort) 5. 快速排序(Qu…...
web前端 React 框架面试200题(四)
面试题 97. React 两种路由模式的区别?hash和history? 参考回答: 1: hash路由 hash模式是通过改变锚点(#)来更新页面URL,并不会触发页面重新加载,我们可以通过window.onhashchange监听到hash的改变,从而处…...
5.Fabric的共识机制
在Fabric中,有以下3中典型共识机制。 Solo共识 solo共识机制只能用于单节点模式,即只能有一个Orderer节点,因此,其共识过程很简单,每接收到一个交易信息,就在共识模块的控制下产生区块并广播给节点存储到账本中。 Solo 模式下的共识只适用于一个Orderer节点,所以可以在…...
【safari】react在safari浏览器中,遇到异步时间差的问题,导致状态没有及时更新到state,引起传参错误。如何解决
在safari浏览器中,可能会遇到异步时间差的问题,导致状态没有及时更新到state,引起传参错误。 PS:由于useState是一个普通的函数, 定义为() > void;因此此处不能用await/async替代setTimeout,只能用在返…...
京准:GPS北斗卫星授时信号安全隔离防护装置
京准:GPS北斗卫星授时信号安全隔离防护装置 京准:GPS北斗卫星授时信号安全隔离防护装置 1、主要特点 ★信号加固功能: GPS/BDS单系统信号拒止情况下(包含受到GPS L1欺骗干扰、GPS L1压制干扰、BDS B1欺骗干扰、BDS B1压制干扰&…...
解决方案架构师系列 - AWS - Pinpoint
AWS Pinpoint介绍 Amazon Pinpoint 为营销人员和开发人员提供了一款可自定义的工具,助力他们大规模地开展跨渠道、行业和活动的客户通信。 Amazon Pinpoint是一个全面的客户参与平台,旨在帮助营销人员和开发人员大规模地开展跨渠道、行业和活动的客…...
MF173:将多个工作表转换成PDF文件
我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…...
Docker、containerd、CRI-O 和 runc 之间的区别
容器与 Docker 这个名称并不紧密相关。你可以使用其他工具来运行容器 您可以使用 Docker 或一堆非Docker 的其他工具来运行容器。docker只是众多选项之一,Docker(公司)在生态系统中创建了一些很棒的工具,但不是全部。 容器方面有…...
PRISM-Python 中的规则一个简单的 Python 规则感应系统
欢迎来到雲闪世界.PRISM 是一种现有算法(尽管我确实创建了一个 Python 实现),PRISM 相对简单,但在机器学习中,有时最复杂的解决方案效果最好,有时最简单的解决方案效果最好。然而,当我们希望建立…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
