【C++入门】详解(中)

目录

💕1.函数的重载

💕2.引用的定义

💕3.引用的一些常见问题 

💕4.引用——权限的放大/缩小/平移

 💕5. 不存在的空引用

💕6.引用作为函数参数的速度之快(代码体现)

 💕7.引用的思考 


(最新更新时间——2025.1.9)

一个人的坚持到底有多难

在座的各位都能回答这个问题!


💕1.函数的重载

在C++中,是支持函数的名称重复的,但并不是完全重复

要求这些同名函数作用在同一作用域

且函数的形参不同->:可以是 参数类型不同 或者 参数个数不同 或者 参数顺序不同,这也叫做函数的重载

那么,函数的重载具体是什么呢?代码如下:

 第一种情况:同名函数的形参类型不同——函数的重载

26a001a36ed34a6f846c5765ed193791.png

由代码可见,同名函数的形参是不同的,但是依旧可以运行,没有报错,我们也不必担心编译器会不知道运行哪个函数,因为在我们使用函数传参时,编译器会智能的去辨别类型,进而判断出该用哪个函数

第二种情况:同名函数的参数个数不同——函数的重载
fc5ac47b1a784280a92a24fb7bf919f6.png
由此可见,同名函数的参数的个数不同可以构成函数的重载

第三种情况:同名函数的形参类型顺序不同——函数的重载

52cc16e5d91c440aadaf14bc8f7e5858.png

需要注意的是,形参的顺序不同需要满足同名函数的形参类型不能完全相同,如下:

b14ea0d5fa3a4f4c86e3737fb1b841e1.png

如果这么写的话,编译器也会不知道该调用哪个函数,这叫做调用歧义

注意点:返回值不可以作为函数重载的判断,因为调用时也无法区分


小练习->:

判断下面代码是否构成函数的重载

namespace bit1
{void total(int pa, int pb){cout << "total(int pa, int pb)" << endl;}
}namespace bit2
{void total(int px, int py){cout << "total(int px, int py)" << endl;}
}
int main()
{bit1::total(3, 5);bit2::total(8, 8);
}

答案是否定的,因为两个同名函数并不作用于同一作用域下,所以并不构成函数的重载


💕2.引用的定义

在C++中,提出了“引用”的功能,什么是引用呢?


引用其实就是变量的别名

就相当于,你们班有一个学习特别好的人,数理化每次都是第一,那么这个同学就会获得三个别名,分别是“数学第一”,“物理第一”,“化学第一”,当你说数学第一时,大家知道你说的是他,当你说物理第一时,大家也知道你说的是他,这就叫做别名

引用书写方法->:

f551396be41d46358588cbffcd0d4923.png

我们知道,学习C语言时, & 是取地址的意思,难道在C++中改变了吗?

其实没有,只有在你像图中这么使用时才会变为引用的意义

此时,b为a的别名,那么我们调用b的时候,其实就是调用a


问题:我们在创建别名时,是开辟了新的空间吗?

我们可以验证一下:

b7f24dabd7f143eaa72ebf1a3fd8ed26.png

我们发现,b与a的地址一样,所以在引用时,并不会开辟新的空间,只会创建一个“别名”


💕3.引用的一些常见问题 

各位可以思考一下,这种情况下a,b会交换吗?

#include<iostream>
using namespace std;
void Swap(int& ta, int& tb)
{int tmp = ta;ta = tb;tb = tmp;
}int main()
{int a = 100;int b = 20;Swap(a, b);cout << a <<" " << b << endl;
}

答案是会的,为什么?


我们先回到C语言时学习的交换,在C语言中,我们知道,如果不传地址的话,就无法改变两者的值,因为形参是实参的一份临时拷贝,swap函数会将a与b复制一份传给ta,tb,这时候会开辟新的地址空间,操作的是 ta 与 tb

3782cdfd52684aceb213d191f84dbe23.png


但是这样却交换了,首先我们知道,除去变量名就是变量类型,我们在形参中的变量类型是int&类型,这种类型本身就是引用,是属于一个别名,所以我们将a传过去时,会将a的引用

传给形参,实际上发生的是int& ta = a,int& tb = b;

此时ta与tb就是别名,而上述我们提到过,引用是不会开辟新的空间的,所以实际上操作的就是a与b

dc2785ce4d56485a936442da06100ea6.png


注意小点1->:

在使用引用的过程中,我们也可以给别名引用,起出别名的别名,如下->:

b4e357b49db542d3b6be6df0b293cff6.png


 注意小点2->:

在使用引用时,必须进行初始化,不可以说创建int&后就扔掉了,等一会有需要再用,代码如下:

744f6ba213a34b1595105681d3d4d2c8.png


 注意小点3->:

一个变量可以有多个引用,但一个引用只可以绑定一个变量

#include<iostream>
using namespace std;int main()
{	int a = 10;int& b = a;int& c = a;int l = 100;c = l;}

以上代码的含义是什么?

A.让l赋值给C?

B.让c成为l的别名?


答案是A,引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体,所以这里是赋值

💕4.引用——权限的放大/缩小/平移

 在C++中,存在权限的放大,缩小,以及平移的问题,那么什么是权限的放大/缩小/平移呢?

请看代码->:

个人认为,权限的放大可以分为地址类与非地址类,首先讲解非地址类


非地址类->:

	//非地址时//权限的平移int a1 = 10;int& b1 = a1;//权限的缩小int a2 = 100;const int& b2 = a2;//权限的放大const int a3 = 100;//int& b3 = a3;  这里是错误写法//正确书写 const int& b3 = a3;

权限的平移(合法)->:

我们的变量a1是 int 类型的,而引用的b1也是 int 类型的,这说明类型的功能没有改变,属于权限的平移


权限的缩小(合法)->:

我们的a2是 int 类型的,而引用的b2是const int 类型的,我们知道,被const修饰后的变量,只可以读不可以修改,所以我们把一个既可以读又可以修改的变量,取了一个只可以读不可以修改的别名,这是属于权限的缩小,是合法的


权限的放大(非法)->:

我们的a3是const int 类型的,只可以读不可以修改,但是如果我们运行了错误的写法

(int& b3 = a3),那么就把只能读不能改的变量,取了一个即可以读又可以改的别名,这样的话,我们的b3是可以修改的,但是b3是a3的别名,我的本体不可以被修改,我的分身却可以修改我,这是权限的放大,是非法的


地址类->:

	//地址情况int a1 = 10;//权限的平移int* p1 = &a1;int*& pp = p1;//权限的缩小int* pp1 = &a1;const int* p2 = pp1;//权限的放大const int* p3 = &a1;int* p4 = p3;int*& p4 = p3;

原理与上述相同,但需要注意的是,权限的缩小并没有运用到别名,只是单纯的赋值,这也说明,权限的放大/缩小/平移,并不只是单独存在于引用之中,同时我们还需要注意一下写法

	//权限的缩小int* pp1 = &a1;const int* p2 = pp1;const int*& p3 = pp1;	//	错误的写法

为什么?因为它单纯触发了C++中const的安全保障,为了防治你用错间接修改上,所以禁止使用


思考->:

    //这是权限的放大吗?int a1 = 10;int b1 = 20;const int& r1 = a1 + b1;

答案是,是的,因为a1+b1得到的值是可以修改的,而r1不可以修改,所以这也是权限的放大


 💕5. 不存在的空引用

在我们使用引用时,是不可以实现空引用的,如下->:

ab23cf5aec6f489f8c638a912a34c949.png

但是有一种写法是合法的->:如下:

	int* ptr = NULL;int& r = *ptr;cout << r << endl;

只不过打印不出来什么


💕6.引用作为函数参数的速度之快(代码体现)

运行以下代码,可以知道引用作为参数的运行快在哪里

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
using namespace std;
struct A { int a[10000]; 
};
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{A a;// 以值作为函数参数size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc1(a);size_t end1 = clock();// 以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc2(a);size_t end2 = clock();// 分别计算两个函数运行结束后的时间cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}int main()
{TestRefAndValue();return 0;
}

我们可以发现,不以引用作为参数的话,那么在运行函数前就会重新开辟新的空间来作为临时变量,这需要消耗大量的栈佂与时间

而如果用引用作为参数的话,那么就不会开辟新的地址,因为实际运行的是A& a = i;这属于引用创建的别名,没有开辟新的空间,正如上述所讲,地址没有发生改变


 💕7.引用的思考 

int main()
{// 权限可以平移/缩小 不能放大double d = 12.34;// 类型转换int i = d;int& r2 = d;//报错const int& r1 = d;//不报错//r1不能修改dreturn 0;
}

我们知道,在 int i = d 时,因为类型的不同,所以它其实是有一个隐式类型转换的,此时,会将 d 复制一份并强制转化为 int类型 再赋值给 i ,所以 i 其实是复制 d 的一份 int 类型的值

其次当我们使用int& r2 = d时,因为d是double类型的,r2是int类型的,这里属于运算,还是会存在隐式类型转换,所以 r2 其实是 强制转化后的 d ,但是因为强制转化所生成的值是临时变量,临时变量是不可修改的,但是int& r2是可以修改的,这属于权限的放大,所以是不对的

那为什么我们使用const int& r1 = d 时,就不会报错呢?这里其实还是会因为类型的不同而存在强制类型转化只要是运算就会存在强制类型转化,此时d还是会被复制一份并强制转化为int类型,而 r1 就是强制 int 类型的 d 的别名,但是被const修饰了,那就说明我们不可以对其进行修改值,属于权限的平移,也就不会报错,如果你想打印 r1 的话,你会发现打印出来的是 12 

5cbe13136c2b4135a9f151baa91fa5ef.png

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

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

相关文章

springboot整合mysql

1.首先在pom.xml中添加依赖&#xff1a; <!-- MySQL Driver --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><!-- Druid连接池 -->…

Windows C++开发环境:VSCode + cmake + ninja + msvc (cl.exe) + msys2/bash shell

这套环境的作用/优点 VSCode&#xff1a;代替Visual Studio, 启动迅速&#xff0c;内存占用小cmake: 与linux一致的构建系统ninja msvc: 用ninja作为cmake的generator, 配合msvc生成工具完成C工程的编译和链接 msvc作为编译工具&#xff0c;而不是msys2或mingw64的gcc&#x…

《Opencv》图像的旋转

一、使用numpy库实现 np.rot90(img,-1) 后面的参数为-1时事顺时针旋转&#xff0c;为1时是逆时针旋转。 import cv2 import numpy as np img cv2.imread(./images/kele.png) """方法一""" # 顺时针90度 rot_1 np.rot90(img,-1) # 逆时针90度…

CES 2025|全面拥抱端侧AI,美格智能在CES发布系列创新成果

要点&#xff1a; ▶ 在AI机器人领域&#xff0c;以高算力AI模组助力发布“通天晓”人形机器人和2款全新微小型AI机器人 ▶ 在AI硬件领域&#xff0c;发布消费级AI智能体产品——AIMO&#xff0c;引领个人专属的大模型时代 ▶ 在5G通信领域&#xff0c;发布全新5GWiFi-7 CPE…

Python自学 - 类进阶(生成器)

<< 返回目录 1 Python自学 - 类进阶(生成器) 生成器是一种特殊的迭代器&#xff0c;它允许在迭代过程中暂停和恢复函数的执行。生成器的特点&#xff1a; 使用yield返回值&#xff0c;而不是return 函数执行到yield时会进入暂停状态并保存状态。 再次执行函数时&#…

Spring Boot 支持哪些日志框架

Spring Boot 支持多种日志框架&#xff0c;主要包括以下几种&#xff1a; SLF4J (Simple Logging Facade for Java) Logback&#xff08;默认&#xff09;Log4j 2Java Util Logging (JUL) 其中&#xff0c;Spring Boot 默认使用 SLF4J 和 Logback 作为日志框架。如果你需要使…

SpringBoot的@Scheduled和@Schedules有什么区别

Scheduled 的详细解析 参数详解 cron: 使用Cron表达式来指定复杂的调度模式。Cron表达式的格式如下&#xff1a; 秒&#xff08;0-59&#xff09;分钟&#xff08;0-59&#xff09;小时&#xff08;0-23&#xff09;日&#xff08;1-31&#xff09;月&#xff08;1-12 或 JAN-…

js基础---书写位置

js基础—书写位置 内部 直接写在html文件里面&#xff0c;用script标签包住 规范 &#xff1a;script 标签写在上面 代码演示 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport"…

SpringBoot操作spark处理hdfs文件

SpringBoot操作spark处理hdfs文件 1、导入依赖 <!-- spark依赖--><dependency><groupId>org.apache.spark</groupId><artifactId>spark-core_2.12</artifactId><version>3.2.2</version></dependency><depend…

Jaeger UI使用、采集应用API排除特定路径

Jaeger使用 注&#xff1a; Jaeger服务端版本为&#xff1a;jaegertracing/all-in-one-1.6.0 OpenTracing版本为&#xff1a;0.33.0&#xff0c;最后一个版本&#xff0c;停留在May 06, 2019。最好升级到OpenTelemetry。 Jaeger客户端版本为&#xff1a;jaeger-client-1.3.2。…

PySide6-UI界面设计

导论&#xff1a; PySide6和PyQt都是Python对Qt框架的绑定&#xff0c;允许开发者使用Qt创建平台的GUI应用程序。如果你正在开发商业项目&#xff0c;或者需要使用最新的QT6特性&#xff0c;PySide6是一个更好的选择。如果你更倾向于一个成熟的社区和丰富的资源&#xff0c;Py…

使用 Multer 上传图片到阿里云 OSS

文件上传到哪里更好&#xff1f; 上传到服务器本地 上传到服务器本地&#xff0c;这种方法在现今商业项目中&#xff0c;几乎已经见不到了。因为服务器带宽&#xff0c;磁盘 IO 都是非常有限的。将文件上传和读取放在自己服务器上&#xff0c;并不是明智的选择。 上传到云储存…

电机控制的数字化升级:基于DSP和FPGA的仿真与实现

数字信号处理器&#xff08;DSP&#xff0c;Digital Signal Processor&#xff09;在工业自动化领域的应用日益广泛。DSP是一种专门用于将模拟信号转换成数字信号并进行处理的技术&#xff0c;能够实现信号的数字滤波、重构、调制和解调等多项功能&#xff0c;确保信号处理的精…

微服务的CAP定理与数据一致性抉择

分布式系统中的CAP定理&#xff0c;包括一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;和分区容错性&#xff08;Partition Tolerance&#xff09;三个核心要素。 微服务是分布式系统的一种表现形式&#xff0c;以及用户对于系统是分…

leetcode_2816. 翻倍以链表形式表示的数字

2816. 翻倍以链表形式表示的数字 - 力扣&#xff08;LeetCode&#xff09; 搜先看到这个题目 链表的节点那么多 已经远超longlong能够表示的范围 那么暴力解题 肯定是不可以的了 我们可以想到 乘法运算中 就是从低位到高位进行计算 刚开始 我想先反转链表 然后在计算 然后在进…

Element Plus 之 el-table相同行合并(通用函数),相同列合并(自行判断需合并的字段以及相应的列下标)

展示 代码 <el-table :data"tableData" border style"width: 100%" :span-method"objectSpanMethod"><el-table-column prop"date" label"Date" width"180" align"center" /><el-table…

QT中引入OpenCV库总结(qmake方式和cmake方式)

文章目录 前言opencv环境配置一、opencv库获取的两种方式二、qmake和cmake配置2.1、 qmake2.2、cmake2.2.1、引入opencv示例 三、qt与opencv对应关系四、问题 前言 我的软件环境&#xff0c;写在前面 Windows10QT5.12.12VS2017OpenCV4.5.4 opencv环境配置 一、opencv库获取…

[石榴翻译] 维吾尔语音识别 + TTS语音合成

API网址 丝路AI平台 获取 Access token 接口地址&#xff1a;https://open.xjguoyu.cn/api/auth/oauth/token&#xff0c;请求方式&#xff1a;GET&#xff0c;POST Access token是调用服务API的凭证&#xff0c;调用服务API之前需要获取 token。每次成功获取 token 以后只有…

webrtc之rtc::ArrayView<const uint8_t>

rtc::ArrayView<const uint8_t> 是 WebRTC&#xff08;或其他基于 rtc 命名空间的库&#xff09;中常见的一个类型&#xff0c;它通常用于表示一块 只读的内存区域&#xff0c;该内存区域由一系列 uint8_t 类型&#xff08;无符号 8 位整数&#xff09;元素组成。 1. rt…

汽车供应链关键节点:物流采购成本管理全解析

在汽车行业&#xff0c;供应链管理是一项至关重要的任务。汽车制造从零部件的生产到整车的交付&#xff0c;涉及多个环节&#xff0c;其中物流、采购与成本管理是核心节点。本文将深入分析这些关键环节&#xff0c;探讨如何通过供应商管理系统及相关工具优化供应链管理。 一、…