当前位置: 首页 > news >正文

【c++学习】入门c++(中)

目录

  • 一. 前言
  • 二. 函数重载
    • 1. 概念
    • 2.函数名修饰规则
    • 三 .引用(&)
      • 1. 概念
      • 2. 引用特性
      • 3.应用
        • 1.做参数
        • 2. 做返回值
        • 3. 传值、传引用效率比较
        • 4.引用和指针的区别
    • 四 . 结语

一. 前言

小伙伴们大家好,今天我们继续学习c++入门知识,今天的内容主要是

二. 函数重载

1. 概念

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这 些同名函数的形参列表(参数个数 或 类型 或类型顺序)不同,常用来处理实现功能类似数据类型 不同的问题

可以理解为一词多义,比如一句话**“谁也赢不了”**,分别用在国乒乓队和国足的身上,就是两种截然不同的意思,大家细品。

int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}

然而c语言不支持函数重载,上述代码运行会直接报错。
三种重载方式:

1· 参数类型不同
2、参数个数不同
3、参数类型顺序不同

//参数类型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}// 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;
}

2.函数名修饰规则

由之前的知识我们知道,函数调用需要建立栈帧,那么编译器是如何精确找到这些同名函数的地址呢?

c语言是根据函数名寻找函数,如果函数名相同,就会起冲突。
而c++通过函数名重载对函数的地址进行修饰

在这里插入图片描述
windows下的函数修饰名规则太复杂,所以我们转到Linux上对其讲解

Linux下修饰规则:格式:_ Z + 函数名称长度 + 函数名 + 类型首字母

代码段:

    1 #include<stdio.h>2                                                                                                                                                                                      3 void  add(int a,int b)4 {                        5 } 6  7 int main(){8            9   return 0;10 }          

进行编译形成可执行文件后,还需借助objdump -S exeName 查看修饰规则

在这里插入图片描述
结果为
在这里插入图片描述
我们发现c语言是直接根据函数名查找对应函数

改图为c++编译后的代码段
在这里插入图片描述

所以说:

对于相同名字的函数,函数重载就根据参数的类型,顺序,个数,以这些为基准,来区别不同的函数

但是不同返回值的函数不能构造函数重载

对于返回值不同的其他都相同的函数来说,在函数调用时,无法进行区分返回值,分不清调用哪个函数,不仅仅是因为函数返回值不在修饰规则内。

三 .引用(&)

1. 概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空 间,它和它引用的变量共用同一块内存空间

通俗来说就是取外号:
你很瘦,他人给你取了个外号叫“竹竿”,他的意思就是”竹竿“也代表了你

定义:

类型& 引用变量名(对象名) = 引用实体

实现如下:

int a = 10;
int& b = a;b = 20;
cout << a << endl;

在这里插入图片描述
可以看出,a和b共用一个地址,且b为(int &)类。

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

2. 引用特性

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再不能引用其他实体

前俩条很好理解,最后一个是指当引用初始化之后,就不能改变引用的指向了

在这里插入图片描述

可以看出,b的值变成了20,a的值也改变成为了20,但b的地址没有改变,说明了
引用一旦引用一个实体,再不能引用其他实体

3.应用

1.做参数

还记得c语言中的交换函数怎么实现的吗

void swap(int *a ,int *b)
{int tmp=*a;*a=*b;*b=tmp;
}

是不是感觉十分别扭,既要传指针,又要进行解引用,
现在我们可以用引用来进行简化

void swap(int& a ,int& b)
{int tmp=a;a=b;b=tmp;
}

传递过来的都是实参的别名,可以直接修改,无需解引用

2. 做返回值

看如下代码:

int add(int a, int b)
{int c = a + b;return c;
}int main()
{int ret = add(1, 2);cout << ret << endl;return 0;
}

我们在调用函数时,会建立函数栈帧,对于传值返回,如上述代码的add()函数,在函数调用完成后,函数栈帧销毁,c变量也会销毁,所以传会的并不是变量c,而是c的一份拷贝,是一个临时变量。
但是临时变量在哪?

如果 c 比较小(4/8 byte),一般是寄存器充当临时变量。
如果 c 比较大,临时变量放在调用 add 函数的栈帧中。

如果定义一个静态的变量呢,static修饰的变量储存于静态区,不受函数栈帧的影响,那么返回他会不会进行拷贝呢,答案是会的。
那么就会产生浪费,如何进行规s避呢

我们试一试传引用返回

int& add(int a, int b)
{int c = a + b;return c;
}int main() {int& ret = add(1, 2);cout << ret << endl;add(10, 20);cout << ret << endl;return 0;
}

运行结果:
在这里插入图片描述
可知,ret为int&类,在第一次调用add()函数栈帧销毁后,ret任可以访问当初函数c的地址,所以在第二此调用add()后,ret的值被改为30;
也就是非法访问

引用返回有一个原则:

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

3. 传值、传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低

在这里插入图片描述
通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大。

4.引用和指针的区别

int main()
{
//引用
int a = 10;
int& ra = a;
ra = 20;
//指针
int* pa = &a;
*pa = 20;
return 0;
}

我们看看反汇编码
在这里插入图片描述
发现,指针和引用的底层逻辑是一样的。
所以:
从语法概念上来说,引用是没有开辟空间的,而指针是开辟了空间的
但是:
从反汇编代码上来看,引用其实是开空间的,并且实现方式和指针一样,引用其实也是用指针实现的。

引用和指针的不同点:

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

四 . 结语

大家好,我是展轩,
本次博客学习就到这里,如果觉得有帮助的话,记得
一键三连哦ヾ(≧▽≦*)o。
在这里插入图片描述

http://www.lryc.cn/news/12286.html

相关文章:

  • 论文阅读_AlphaGo_Zero
  • 一文教你用Python创建自己的装饰器
  • 华为OD机试 - 任务总执行时长(JS)
  • pytorch离线快速安装
  • 华为OD机试 - 数组合并(JS)
  • 不要让GPT成为你通向“学业作弊”的捷径——使用GPT检测工具来帮助你保持正确的方向
  • 基于matlab的斜视模式下SAR建模
  • 15-基础加强-1-类加载器反射
  • 基于SSM,Spring, BootStrap 毕业设计管理系统的设计与实现
  • 一招鉴别真假ChatGPT,并简要介绍ChatGPT、GPT、GPT2和GPT3模型之间的区别和联系
  • 华为OD机试 - 特异性双端队列(JS)
  • Nginx自动封禁可疑Ip
  • 分布式事务--理论基础
  • Matlab数学建模常用算法及论文插图绘制模板资源合集
  • C语言【动态内存管理 后篇】
  • 四大步骤,教你彻底关闭Win10自动更新
  • 通信算法之一百零四:QPSK完整收发仿真链路
  • 时间复杂度(超详解+例题)
  • 【Java面试总结】Maven篇
  • 【每日一题Day123】LC1792最大平均通过率 | 堆
  • [安装之5] Mac pro更换大内存固态硬盘实践教程
  • 04 Python变量的声明与使用
  • LeetCode 2418. 按身高排序
  • 一文了解Hotspot虚拟机下JAVA对象从创建到回收的生命周期
  • 【Java基础】Java对象创建的几种方式
  • 社保缴费满15年就可以不缴了?6个很多人最关心的问题权威解答来了
  • 关于HDFS
  • C++入门:类 对象
  • Python生日系统
  • < CSDN周赛解析:第 28 期 >