类和对象——相关的零碎知识
前提提示:
其实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 相对简单,但在机器学习中,有时最复杂的解决方案效果最好,有时最简单的解决方案效果最好。然而,当我们希望建立…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
五、jmeter脚本参数化
目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...
C#最佳实践:为何优先使用as或is而非强制转换
C#最佳实践:为何优先使用as或is而非强制转换 在 C# 的编程世界里,类型转换是我们经常会遇到的操作。就像在现实生活中,我们可能需要把不同形状的物品重新整理归类一样,在代码里,我们也常常需要将一个数据类型转换为另…...
