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

news2025/1/12 7:20:20

目录

💕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不能修改d
	return 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.coloradmin.cn/o/2275378.html

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

相关文章

【题解】—— LeetCode一周小结53

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结52 30.二叉树中的链表 题目链接&#xff1a;1367. 二叉树中的链…

Vue方法、计算机属性及侦听器

数组变化侦测 假设我们写了一个数组&#xff0c;现在想让该数组中新增一条数据,那么如何去实现呢&#xff1f; <template><h3>数组变化侦听</h3><button click"addListHandler">添加数据</button><ul><li v-for"(item…

TIOBE编程语言排行靠前的编程语言的吉祥物

Python的吉祥物&#xff1a;小蟒蛇 Python语言的吉祥物是一只名叫"Pythonidae"&#xff08;或简称"Py"&#xff09;的小蟒蛇。这个吉祥物由Tobias Kohn设计于2005年&#xff0c;它的形象借鉴了真实的蟒蛇&#xff0c;但加入了一些可爱和友善的特点。小蟒蛇…

Linux (CentOS) 安装 Docker 和 Docker Compose

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode︱ Gitee ︱ Github &#x1f496; 欢迎点赞 &#x1f44d; 收藏 ⭐评论 …

Unity热更新 之 Addressables(2) 本地/远端打包 流程测试

基础篇&#xff1a;Unity热更新 之 Addressables(1) 资源基础加载-CSDN博客 基础方法来源于唐老狮,我也是初学热更这一块&#xff0c;所有不保证步骤完全正确&#xff0c;如有不足还请斧正 目录 0.前提 1.本地打包 1.1.资源放入包 1.2.简化路径名称给出标签(如有需要的话) …

Openstack持久存储-Swift,Cinder,Manila三者之间的区别

总结不易&#xff0c;给个三连吧&#xff01;&#xff01;&#xff01; 补充&#xff1a; 文件共享存储服务Manila 在OpenStack生态系统中&#xff0c;Cinder和Manila分别提供了两种不同类型的存储服务&#xff0c;类似于传统的SAN&#xff08;存储区域网络&#xff09;和NAS&…

【TI毫米波雷达】DCA1000不使用mmWave Studio的数据采集方法,以及自动化实时数据采集

【TI毫米波雷达】DCA1000不使用mmWave Studio的数据采集方法&#xff0c;以及自动化实时数据采集 mmWave Studio提供的功能完全够用了 不用去纠结用DCA1000低延迟、无GUI传数据 速度最快又保证算力无非就是就是Linux板自己写驱动做串口和UDP 做雷达产品应用也不会采用DCA1000的…

JavaEE之线程池

前面我们了解了多个任务可以通过创建多个线程去处理&#xff0c;达到节约时间的效果&#xff0c;但是每一次的线程创建和销毁也是会消耗计算机资源的&#xff0c;那么我们是否可以将线程进阶一下&#xff0c;让消耗计算机的资源尽可能缩小呢&#xff1f;线程池可以达到此效果&a…

J-LangChain - 复杂智能链流式执行

系列文章索引 J-LangChain 入门 介绍 j-langchain是一个Java版的LangChain开发框架&#xff0c;具有灵活编排和流式执行能力&#xff0c;旨在简化和加速各类大模型应用在Java平台的落地开发。它提供了一组实用的工具和类&#xff0c;使得开发人员能够更轻松地构建类似于LangC…

《HeadFirst设计模式》笔记(上)

设计模式的目录&#xff1a; 1 设计模式介绍 要不断去学习如何利用其它开发人员的智慧与经验。学习前人的正统思想。 我们认为《Head First》的读者是一位学习者。 一些Head First的学习原则&#xff1a; 使其可视化将文字放在相关图形内部或附近&#xff0c;而不是放在底部…

springboot整合h2

在 Spring Boot 中整合 H2 数据库非常简单。H2 是一个轻量级的嵌入式数据库&#xff0c;非常适合开发和测试环境。以下是整合 H2 数据库的步骤&#xff1a; 1. 添加依赖 首先&#xff0c;在你的 pom.xml 文件中添加 H2 数据库的依赖&#xff1a; <dependency><grou…

安装rocketmq dashboard

1、访问如下地址&#xff1a; GitHub - apache/rocketmq-dashboard: The state-of-the-art Dashboard of Apache RoccketMQ provides excellent monitoring capability. Various graphs and statistics of events, performance and system information of clients and applica…

mysql中创建计算字段

目录 1、计算字段 2、拼接字段 3、去除空格和使用别名 &#xff08;1&#xff09;去除空格 &#xff08;2&#xff09;使用别名&#xff1a;AS 4、执行算术计算 5、小结 1、计算字段 存储在数据库表中的数据一般不是应用程序所需要的格式&#xff0c;下面举几个例子。 …

【批量拆分PDF】批量按页码范围拆分PDF并按页码重命名:技术难题与总结

按照页码范围拆分PDF项目实战参考&#xff1a; 【批量个性化拆分PDF】批量拆分PDF只取PDF的首页&#xff0c;批量按照文件大小来拆分PDF&#xff0c;PDF按照目录页码范围批量计算拆分分割文件PDF个性化拆分&#xff08;单个拆分&#xff0c;取首页拆分&#xff0c;按页码计算拆…

MySQL表的增删改查(基础)-上篇

目录 CRUD 新增 查询 (1)全列查询 (2)指定列查询 (3)查询时指定表达式 (4)别名 (5)去重查询 (6)排序查询 (7)条件查询 (8)分页查询 CRUD 即增加(Create)、查询(Retrieve)、更新(Update)、删除(Delete)四个单词的首字母缩写 新增 也可插入中文字符串 查询 (1)全列查…

【论文速读】| 利用大语言模型在灰盒模糊测试中生成初始种子

基本信息 论文标题: Harnessing Large Language Models for Seed Generation in Greyb0x Fuzzing 作者: Wenxuan Shi, Yunhang Zhang, Xinyu Xing, Jun Xu 作者单位: Northwestern University, University of Utah 关键词: Greyb0x fuzzing, Large Language Models, Seed g…

Linux:操作系统简介

前言&#xff1a; 在本片文章&#xff0c;小编将带大家理解冯诺依曼体系以及简单理解操作喜欢&#xff0c;并且本篇文章将围绕什么以及为什么两个话题进行展开说明。 冯诺依曼体系&#xff1a; 是什么&#xff1a; 冯诺依曼体系&#xff08;Von Neumann architecture&#xff…

为什么选择平滑样条?

为什么选择平滑样条&#xff1f; 抗噪声能力&#xff1a; 平滑样条通过引入平滑参数 λ \lambda λ&#xff0c;允许你在以下两者之间找到平衡&#xff1a; 拟合误差&#xff08;与数据的偏离&#xff09;&#xff1a;希望曲线接近数据点。光滑性&#xff08;曲线的平滑程度&a…

边缘计算网关解决车间数据采集的关键问题

随着工业4.0和智能制造的快速发展&#xff0c;车间数据采集与分析已成为提升生产效率、保证产品质量、优化加工过程的关键环节。传统的数据采集方式&#xff0c;如中心化的数据处理模式&#xff0c;在面对海量数据、实时性要求高的工业场景时&#xff0c;往往显得力不从心。边缘…

C语言之assert断言

1.assert的使用形式 #include <assert.h>assert (表达式); (1)在c语言中&#xff0c;宏&#xff0c;是一种预处理指令。assert(表示式) 就是一个宏 (2)表达式必须是一个能计算出真或假的布尔条件&#xff0c;它通常意味着 该表达式是一个能够返回整数值的表达式&#…