【C++那些事儿】函数重载与C++中的“指针“——引用

在这里插入图片描述

君兮_的个人主页

即使走的再远,也勿忘启程时的初心

C/C++ 游戏开发

Hello,米娜桑们,这里是君兮_,我之前看过一套书叫做《明朝那些事儿》,把本来枯燥的历史讲的生动有趣。而C++作为一门接近底层的语言,无疑是抽象且难度颇深的。我希望能努力把抽象繁多的知识讲的生动又通俗易懂,因此,咱们这个讲解C++的系列博客就叫做《C++那些事儿》啦,而今天我们要讲的内容是C++中的函数重载与引用

  • 好了废话不多说,开始我们今天的学习吧!!

    C++那些事儿

    • 函数重载
      • 函数重载的概念
      • C++支持函数重载的原理--名字修饰(name Mangling)
    • 引用
      • 1.引用概念
      • 2.引用特性
      • 3.常引用
      • 4.引用的使用场景
        • (1).做函数的参数
        • (2).做返回值
      • 传值与传引用效率比较
      • 引用和指针的区别
    • 总结

函数重载

  • 说到函数重载,很多人不理解重载是什么意思,其实它就在我们身边,我来举个例子:
    在这里插入图片描述

一天,你的舍友有节课没去上课,但是碰巧老师上课点名点到他了,老师就问你:他来了吗?
你回答说:如来
老师又问你:到底来没来?
你回答说:如来
于是老师就把你请出教室了

  • 自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了
  • 那在C++中什么是函数重载呢?

函数重载的概念

  • 函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这
    些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型
    不同的问题
#include<iostream>
using namespace std;// 1、参数类型不同
int Add(int x, int y)
{cout << "int类型的Add" <<" "<< x + y << endl;return x + y;
}
double Add(double x, double y)
{cout << "double类型的Add" << " " << x + y << endl;return x + y;
}
// 2、参数个数不同
void f()
{cout << "f()" << endl;
}
void f(int a)
{cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}int main()
{int x = 0;int y = 0;Add(1, 5);f();f(10);f(10, 'b');f('a', 10);return 0;
}

在这里插入图片描述

  • 了解了函数重载的概念和基本使用方法后,很多人可能会想,为什么C++支持函数重载而C不支持函数重载呢?下面我们来讨论一下这个问题

C++支持函数重载的原理–名字修饰(name Mangling)

  • 在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。
    在这里插入图片描述
  • 这里对于没有接触过汇编语言以及编译链接的同学来说非常复杂,也不是我几句话就能说清楚的,因此大家简单理解记住结论即可,我也不会讲太深,随着之后我们C++之旅的进程,当我们接触到更多有关内容后,我再在合适的地方具体解释。
    在这里插入图片描述
  • 这张图片大概展示了在编译链接阶段各阶段进行的操作
  • 由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,我们通过在linux下编译后生成的汇编来讲解这部分内容
  • Linux环境下采用C语言编译器编译后结果
    在这里插入图片描述
  • 结论:在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变
  • 采用C++编译器编译后结果
    在这里插入图片描述
  • 结论:在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中

最终结论(在目前学习阶段记住这个结论就行)
1.C语言之所以没办法支持重载,是因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
2. 如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。

引用

1.引用概念

  • 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
  • 在C++中,引用的作用类似于指针,但是它不开辟空间,在很多情况下,引用是比使用指针更好的选择。
  • 至于起别名,引用就相当于这个变量的外号一样
    比如 孙悟空,如果你是唐僧,你可以叫他悟空
    如果你是猪八戒或者沙僧,你可以叫他大师兄
    如果你是某地界的土地神,你可以叫他孙大圣
    如果你是他的死对头,你可以叫他泼猴或者弼马温…
  • 上述的这些,都是孙悟空的"引用:,也就是别名
    在这里插入图片描述
    类型& 引用变量名(对象名) = 引用实体;
void Test()
{int a = 10;int& ra = a;//<====定义引用类型printf("%p\n", &a);printf("%p\n", &ra);
}int main()
{Test();
}

在这里插入图片描述

  • 引用与原变量指向同一块空间

  • 注意:引用类型必须和引用实体是同种类型的

2.引用特性

  • 1. 引用在定义时必须初始化
  • 2. 一个变量可以有多个引用
  • 3. 引用一旦引用一个实体,再不能引用其他实体
void Test()
{int a = 10;int& ra = a;//<====定义引用类型int& b = a;//一个变量可以有多个别名printf("%p\n", &a);printf("%p\n", &ra);printf("%p\n", &b);
}

在这里插入图片描述

  • 多个引用仍然指向同一块空间
    在这里插入图片描述
  • 必须初始化,不然会报错

3.常引用

void TestConstRef()
{
const int a = 10;
//int& ra = a; // 该语句编译时会出错,a为常量
const int& ra = a;
}
  • 最常见的一种常引用,我们知道引用作为变量的别名,当改变引用的值时,是会改变变量的值的,因此当变量被const修饰时,它的引用也必须用const修饰
void TestConstRef()
{// int& b = 10; // 该语句编译时会出错,b为常量
const int& b = 10;
double d = 12.34;
//int& rd = d; // 该语句编译时会出错,类型不同
const int& rd = d;
}
  • 当我们直接吧一个常量给一个引用时,必须加const,原因与第一种情况相同,而常量就更不可能让你通过引用来修改它的值了
void TestConstRef()
{
double d = 12.34;
//int& rd = d; // 该语句编译时会出错,类型不同
const int& rd = d;
}
  • 这里是存在一个类型的隐式转换的,把double类型的转换成int型,这里类型发生了转换,因此我们也不能通过别名来修改变量,因此必须加const

4.引用的使用场景

(1).做函数的参数

void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
  • 和指针在这里的使用方法是类似的,就不过多展开了

(2).做返回值

int& Count()
{
static int n = 0;
n++;
// ...
return n;
}

注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

  • 下面我们来看一个例子
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :"<< ret <<endl;
return 0;
}

在这里插入图片描述

  • 因此,当我们运行时出现这种结果,也就不奇怪了
    在这里插入图片描述
  • 那应该怎么解决上述的这种问题呢?
  • 很简单,我们让函数解释时,不会释放申请的空间就好了
int& Add(int a, int b)
{static int c = a + b;return c;
}
int main()
{int& ret = Add(1, 2);Add(3, 4);cout << "Add(1, 2) is :" << ret << endl;return 0;
}

在这里插入图片描述

传值与传引用效率比较

  • 以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。
  • 总的来说,你在这里可以暂时把引用类比成指针来使用,等之后学习了类和对象之后,才能更加明白引用在使用时候的妙处

引用和指针的区别

  • 在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
  • 在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
int main()
{//int& ret = Add(1, 2);char c = 'a';char& rc = c;char* rrc = &c;cout << "&rc"<<" "<< sizeof(c) << endl;cout << "rrc" <<" "<< sizeof(rrc) << endl;return 0;
}

在这里插入图片描述

  • 在这里编译器告诉我们引用占一个字节,而指针占8个字节,可事实真的如此吗?
    在这里插入图片描述
  • 通过底层的汇编代码,我们可以知道,实际上,引用是按指针方式实现的是占空间的,至于为什么编译器告诉你它不占空间,因为在C++规定时说引用是一个别名是不占空间的,它总不能自己打自己脸呀
    在这里插入图片描述

引用与指针的其他区别点

1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
2. 引用在定义时必须初始化,指针没有要求
3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体
4. 没有NULL引用,但有NULL指针
5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)
6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
7. 有多级指针,但是没有多级引用
8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
9. 引用比指针使用起来相对更安全


总结

  • 好啦,我们今天的内容就先到这里啦!今天讲解了函数重载与引用使用方法以及有关它们使用的细节和注意事项,这两块的知识点会一直伴随你C++学习之路,是非常重要的,因此希望大家把有关的重点和难点多看几遍加深理解。

  • 有任何的问题和对文章内容的疑惑欢迎在评论区中提出,当然也可以私信我,我会在第一时间回复的!!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下再走呗。你们的支持就是我更新的动力!!!

**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**

在这里插入图片描述

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

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

相关文章

为什么RTX 4090更受欢迎

RTX 4090作为顶级显卡&#xff0c;凭借高性能和高图形处理能力&#xff0c;特别适合游戏、专业图形设计和人工智能领域&#xff0c;备受专业游戏玩家和高性能计算需求开发者的青睐。 RTX 4090高速复杂的计算能力 RTX 4090 GPU拥有 760 亿个晶体管、16384 个 CUDA 核心和 24 GB…

nestjs10.x使用jwt生成token

1 安装依赖&#xff1a; pnpm install --save nestjs/jwtpnpm install passport passport-jwt nestjs/jwtpnpm install types/passport-jwt --save-dev 2 可以使用命令新建auth鉴权文件夹 nest g mo auth // auth.module.ts nest g s auth // auth.service.ts nest g co …

杠杆和保证金有什么关系?WeTrade众汇一个公式讲清楚

在交易中杠杆其实就是一种期权&#xff0c;它能增加交易者作为抵押品的资金&#xff0c;以建立和维持头寸。 例如&#xff0c;1:100的操作杠杆&#xff0c;在这种情况下&#xff0c;意味着开立1000单位基础货币的头寸&#xff0c;交易者将需要少100倍的资金&#xff0c;即10个…

C++常量和变量

甲流疫情死亡率 甲流并不可怕&#xff0c;在中国&#xff0c;它的死亡率并不是很高。根据截至2009年12月22日各省报告的甲流确诊数和死亡数&#xff0c;计算甲流在各省的死亡率 输入 一行&#xff0c;有两个整数&#xff0c;第1个为确诊数&#xff0c;第2个为死亡数 输出 一…

学习Java的第四天

目录 一、if选择结构 1、基本if选择结构 语法结构&#xff1a; 流程图&#xff1a; 示例&#xff1a; 2、if-else 选择结构 语法结构&#xff1a; 流程图&#xff1a; 示例&#xff1a; 3、多重if选择结构 语法结构&#xff1a; 流程图&#xff1a; 示例&#xff1a…

【Docker】若依ruoyi项目部署

一 搭建局域网 1 # 搭建net-ry局域网&#xff0c;用于部署若依项目docker network create net-ry --subnet172.68.0.0/16 --gateway172.68.0.1 # 注意1&#xff1a;关闭宿主机的防火墙&#xff0c;否者容器内部的MySQL、redis等服务&#xff0c;外部访问不了&#xff1b;开放…

【REST2SQL】12 REST2SQL增加Token生成和验证

【REST2SQL】01RDB关系型数据库REST初设计 【REST2SQL】02 GO连接Oracle数据库 【REST2SQL】03 GO读取JSON文件 【REST2SQL】04 REST2SQL第一版Oracle版实现 【REST2SQL】05 GO 操作 达梦 数据库 【REST2SQL】06 GO 跨包接口重构代码 【REST2SQL】07 GO 操作 Mysql 数据库 【RE…

Docker_搭建跨服务器网络通讯(swarm 集群)

本文目录 一、如何搭建docker的跨服务器网络1、在主服务器上初始化docker swarm 集群2、其他服务器节点加入到创建好的集群中3、检验集群是否搭建成功4、创建overlay类型的docker网络 二、如何部署服务1、docker部署2、docker-compose部署 一、如何搭建docker的跨服务器网络 1…

《小学科学》是什么级别的期刊?是正规期刊吗?能评职称吗?

问题解答&#xff1a; 问&#xff1a;《小学科学》期刊是正规期刊吗&#xff1f; 答&#xff1a;是正规期刊&#xff0c;下面会有具体介绍 问&#xff1a;《小学科学》期刊是什么级别的&#xff1f; 答&#xff1a;省级&#xff1b;主管单位&#xff1a;长春出版传媒集团有…

unicloud 创建云函数并使用云函数

云函数是什么 云函数即在云端&#xff08;服务器端&#xff09;运行的函数。 从 HBuilderX 3.4起&#xff0c;新增了云函数的扩展版&#xff0c;云对象。 开发者无需购买、搭建服务器&#xff0c;只需编写代码并部署到云端即可在客户端&#xff08;App/Web/小程序等&#xf…

【Linux】第一个小程序--进度条

这篇博客要综合利用以前的知识&#xff0c;来实现一个进度条程序~ 目录 换行&回车 缓冲区 实现简单的倒计时 实现进度条 version1 version2 在开始写这个小程序之前&#xff0c;我们先学习一些预备知识&#xff1a; 换行&回车 缓冲区 在我们运行这个程序时&…

如何阅读“计算机界三大神书”之一 ——《计算机程序的构造和解释》SICP

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

STM32CubeMX学习笔记17--- FSMC

1.1 TFTLCD简介 TFT-LCD&#xff08;thin film transistor-liquid crystal display&#xff09;即薄膜晶体管液晶显示器。液晶显示屏的每一个像素上都设置有一个薄膜晶体管&#xff08;TFT&#xff09;&#xff0c;每个像素都可以通过点脉冲直接控制&#xff0c;因而每个节点都…

论文阅读:Scalable Diffusion Models with Transformers

Scalable Diffusion Models with Transformers 论文链接 介绍 传统的扩散模型基于一个U-Net骨架&#xff0c;这篇文章提出了一种新的扩散模型结构&#xff0c;将U-Net替换为一个transformer&#xff0c;并将这种结构称为Diffusion Transformers (DiTs)。他们还发现&#xff…

python77-Python的函数参数,个数可变参数

很多编程语言都允许定义个数可变的参数,这样可以在调用函数时传入任意多个参数。Python当然也不例外,Python 允许在形参前面添加一个星号(*),这样就意味着该参数可接收多个参数值,多个参数值被当成元组传入。下面程序定义了一个形参个数可变的函数。 # !/usr/bin/env pyth…

阿里云服务器使用教程_2024建站教程_10分钟网站搭建流程

使用阿里云服务器快速搭建网站教程&#xff0c;先为云服务器安装宝塔面板&#xff0c;然后在宝塔面板上新建站点&#xff0c;阿里云服务器网aliyunfuwuqi.com以搭建WordPress网站博客为例&#xff0c;来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流…

Vscode连接远程服务器失败解决方案

一、 could not establish connection to “XXX” 尝试使用Remote-SSH插件连接远程的服务器&#xff0c;但是配置显示出错&#xff0c;端口显示试图写入的管道不存在&#xff0c;弹出窗口显示could not establish connection to “XXX” 二、检查Windows的OpenSSH 1.检索是否…

Java中注解@RequestParam 和 @ApiParam详解

一、RequestParam 和 ApiParam的常用属性 RequestParam 和 ApiParam 是在 Spring MVC 控制器方法中使用的注解&#xff0c;它们分别服务于不同的目的&#xff1a; RequestParam RequestParam 是 Spring MVC 中用来处理 HTTP 请求参数的注解&#xff0c;主要用于绑定请求中的查…

数据分析项目[开发中]

学习进度记录&#xff1a; 12.7&#xff1a; 教程链接&#xff1a;智能 BI 项目教程(一) (yuque.com) 前端&#xff1a; Ant Design Pro&#xff1a;开始使用 - Ant Design Pro​​​​​​ 然后安装依赖 yarn install 去除不需要的&#xff1a; 移除国际化 【报错】 …

【数据结构与算法】二分查找题解(二)

这里写目录标题 一、81. 搜索旋转排序数组 II二、167. 两数之和 II - 输入有序数组三、441. 排列硬币四、374. 猜数字大小五、367. 有效的完全平方数六、69. x 的平方根 一、81. 搜索旋转排序数组 II 中等 已知存在一个按非降序排列的整数数组 nums &#xff0c;数组中的值不必…