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

news2024/11/15 21:45:32

在这里插入图片描述

君兮_的个人主页

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

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.coloradmin.cn/o/1125896.html

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

相关文章

SparkSQL之LogicalPlan概述

逻辑计划阶段在整个流程中起着承前启后的作用。在此阶段&#xff0c;字符串形态的SQL语句转换为树结构形态的逻辑算子树&#xff0c;SQL中所包含的各种处理逻辑&#xff08;过滤、剪裁等&#xff09;和数据信息都会被整合在逻辑算子树的不同节点中。逻辑计划本质上是一种中间过…

面试时一些不能说的离职原因

“你为什么从上一家公司离职&#xff1f;”这个问题在面试时基本都会被问到&#xff0c;这是无法避免的问题。那么什么样的理由才能做到既反映实际情况&#xff0c;又能得到HR认可呢&#xff1f;以下的几种回答千万不能脱口而出。 1、毫无顾忌地说前公司的坏话 1&#xff09;…

进阶JAVA篇- Map 系列集合的遍历方法与常用API

目录 1.0 Map 集合的说明 1.1 Map 集合的常用方法 1.2 Map 系列集合的特点 2.0 Map 系列集合的遍历方法&#xff08;三种方法&#xff09; 2.1 使用 keySet() 方法遍历 2.2 使用 entrySet() 方法遍历 2.3 使用 forEach() 方法遍历&#xff08;Java 8&#xff09; 1.0 Map 集合的…

数据结构与算法——选择排序法

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

镇魂街武神躯手游攻略,镇魂街武神躯神魂搭配

武神躯是《镇魂街》手游中令人敬畏的角色之一&#xff0c;技能的合理搭配至关重要。下面将详细介绍镇魂街武神躯手游攻略如何搭配武神躯的技能以取得最佳战斗效果&#xff1a; 关注【娱乐天梯】&#xff0c;获取内部福利号 1. 主动技能-刺客之心&#xff1a;这是武神躯的核心主…

python 桌面软件开发-matplotlib画图鼠标缩放拖动

继上一篇在 Java 中缩放拖动图片后&#xff0c;在python matplotlib中也来实现一个自由缩放拖动的例子&#xff1a; python matplotlib 中缩放&#xff0c;较为简单&#xff0c;只需要通过设置要显示的 x y坐标的显示范围即可。基于此&#xff0c;实现一个鼠标监听回调&#xf…

python安装的第三方库

安装第三方库的方式 先按“winR”并输入 cmd 打开命令运行窗口 输入命令&#xff1a; pip install 包名&#xff0c;比如要安装gym包就输入pip install gym 可能存在报错问题及解决办法 报错Could not fetch URL https://pypi.tuna.tsinghua.edu.cn/simple/pip/: There was …

基于Java的美食推荐管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

SparkSQL的Shuffle分区设定及异常数据处理API(去重、缺失值处理)

一、Spark SQL的Shuffle分区数目设定 在允许spark程序时&#xff0c;查看WEB UI监控页面发现&#xff0c;某个Stage中有200个Task任务&#xff0c;也就是说RDD有200分区Partion。 产生原因&#xff1a; 在Spark SQL中&#xff0c;当Job中产生Shuffle时&#xff0c;默认的分区数…

Android乐器在线租借租赁系统+全套手把手视频教程

【项目功能介绍】 功能列表: 本系统包含后台管理和前端app双端系统, 本系统包含三个角色: 管理员,员工,app用户。 后台管理员的功能包含: 登录, 退出, 乐器管理,添加乐器,修改乐器,禁用启用乐器; 乐器器械管理,添加乐器器械,修改乐器器械,启用禁用乐器器械; 订单管理,确定订单…

Node学习笔记之fs模块

fs 全称为 file system &#xff0c;称之为 文件系统 &#xff0c;是 Node.js 中的 内置模块 &#xff0c;可以对计算机中的磁盘进行操 作。 本章节会介绍如下几个操作&#xff1a; 文件写入文件读取文件移动与重命名文件删除文件夹操作查看资源状态 一、文件写入 文件写入就…

Vercel,建站者的福音!!!

前言 各位互联网精神股东大家好&#xff01; 在今年八九月份之前&#xff0c;我所搭建的杂七杂八的个人、团队应用&#xff0c;包括但不限于文档站&#xff0c;博客站&#xff0c;Api服务&#xff0c;线上项目等&#xff0c;他们背后的服务支持可以归纳为以下几种&#xff1a…

Arduion 驱动 ADXL335三轴加速度计模块

Arduion 驱动 ADXL335三轴加速度计模块 简介电气参数原理图接线代码实验结果 简介 ADXL335是一个小&#xff0c;薄&#xff0c;低功率&#xff0c;完整的三轴加速度计&#xff0c;具有信号调节电压输出。该产品测量加速度的最小全尺度范围为3 g。它可以测量倾斜传感应用中重力…

【微信小程序开发】之微信授权登陆

目录 前言 ​编辑一、微信授权登陆介绍 1. 基本概念 2. 微信小程序开发实现微信授权登陆原理流程 3. 小程序中运用微信授权登陆的好处 二、微信授权登陆接口演示 1. 在微信开发工具中导入小程序授权微信登陆前端项目 2. 微信授权登陆的方式 2.1 wx.login 2.2 wx.getUse…

提高查询性能的秘密:深入剖析聚集、辅助、覆盖和联合索引

文章目录 &#x1f34a; 聚集索引&#x1f34a; 辅助索引&#x1f34a; 覆盖索引&#x1f389; 覆盖索引是什么&#xff1f;&#x1f389; 什么情况下优化器会选择使用覆盖索引&#xff1f;&#x1f4dd; 1. 查询操作只需要用到辅助索引中的字段&#x1f4dd; 2. 进行统计操作时…

使用Java实现汉诺塔问题~

我们设A为起始柱子&#xff0c;B为辅助柱子&#xff0c;C为目标柱子 由于盘子只能是大的放在下面&#xff0c;小的放在上面&#xff0c;因此&#xff0c;我们需要先将A柱子除了最下层的盘子都移动至B柱子 如下所示完成了最下层柱子到达它的最终位置&#xff0c;接下来&#xf…

Git(一)Windows下安装及使用Git Bash

目录 一、简介1.1 什么是Git&#xff1f;1.2 Git 的主要特点1.3 什么是 Git Bash&#xff1f; 二、下载三、安装3.1 同意协议3.2 选择安装位置3.3 其他配置&#xff08;【Next】 即可&#xff09;3.4 安装完毕3.5 打开 Git Bash 官网地址&#xff1a; https://www.git-scm.com/…

【React Router】React Router学习笔记

React Router学习笔记 React Router1.什么是React Router?2.为什么要用React Router?3.基础3.1 路由配置3.2 路由匹配原理3.3 History3.3.1 browerHistory3.3.2 hashHistory3.3.3 createMemoryHistory3.3.4 实现示例 3.4 默认路由(IndexRoute)与IndexLink3.4.1 IndexRoute3.4…

javaEE -6(10000详解文件操作)

一&#xff1a;认识文件 我们先来认识狭义上的文件(file)。针对硬盘这种持久化存储的I/O设备&#xff0c;当我们想要进行数据保存时&#xff0c;往往不是保存成一个整体&#xff0c;而是独立成一个个的单位进行保存&#xff0c;这个独立的单位就被抽象成文件的概念&#xff0c…

畅行全球,美格智能SLM750模组锻造出海核心优势

什么是产品认证制度&#xff1f; 国际标准化组织&#xff08;ISO&#xff09;将产品认证定义为&#xff1a;由第三方通过检验评定企业的质量管理体系和样品型式试验来确认企业的产品、过程或服务是否符合特定要求&#xff0c;是否具备持续稳定地生产符合标准要求产品的能力&am…