C++:函数重载、引用
- 一、缺省参数🛫
- 1.1 🚝什么是缺省参数
- 1.2 🚝缺省参数的分类
- a. 全缺省参数
- b. 半缺省参数(部分缺省参数)
- 1.3 🚝注意事项
- 二、函数重载🛫
- 2.1 🚝什么是函数重载
- 2.2 🚝演示
- 2.3 🚝用法注意事项
- a) 不能只有返回值类型不同
- b) 类型顺序相同,形参名字不同不构成函数重载
- c) 相同类型数据,顺序不同不构成函数重载
- 2.4🚝 const 形参
- 三、引用🛫
- 3.1🚝 什么是引用
- 3.2 🚝引用的定义
- 3.3🚝 特性
- a. 在定义时必须初始化
- b. 引用类型的初始值必须是一个对象(不能是常量)
- c. 一个变量可以有多个引用
- d. 一旦引用一个实体,再不能引用其他实体
- 3.4🚝 常引用
- a. const 修饰的常变量
- b. 常量
- c. 不同类型
- 3.5🚝 引用与指针的区别
一、缺省参数🛫
1.1 🚝什么是缺省参数
缺省参数是 声明 或 定义 函数时为函数的参数指定一个缺省值。
在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
缺省参数使用主要规则:调用时你只能从最后一个参数开始进行省略,换句话说,如果你要省略一个参数,你必须省略它后面所有的参数。
👉C++中可以给函数的形参赋值:
这就是给函数的参数指定一个缺省值:
如果不进行传参,就会直接使用缺省值
如果传参,则使用传过来的参数
1.2 🚝缺省参数的分类
a. 全缺省参数
全缺省参数:所有参数都有缺省值
规律见图👆
如果要传参,传递的参数从函数第一个参数开始传递,依次传递
我们可能要问了,如果我只想传递第二个参数(跳过前面的参数直接传后面的),行不行呢?
比如:
当然是错误的,全缺省传参的时候必须从左往右连续的传,不能 “跳着” 传 !
b. 半缺省参数(部分缺省参数)
半缺省参数:函数中的所有参数从最右边往左连续地缺省一部分(当然也可以省一个)
省了,但没完全省
举个栗子:
错误①
部分缺省时就不能不传参了
错误②:
函数中的所有参数从最右边往左连续地缺省
不可以从除倒数第一个参数以外的参数开始缺省:
正确用法:
1.3 🚝注意事项
-
- 半缺省参数必须从右往左依次来给出,不能间隔着给
-
- 缺省参数不能在函数声明和定义中同时出现
-
- 缺省值必须是 常量或者全局变量
-
- C++可以,但是C语言不支持(编译器不支持)
注意第二点:如果声明与定义中同时缺省,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值
在声明时给缺省值,定义的时候不能给
二、函数重载🛫
—— “一词多义” ,即一个函数有多个 “ 意思 ”
2.1 🚝什么是函数重载
定义:如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载( overloaded )函数。
函数重载是函数的一种特殊情况
C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表( 参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题
注意:
①函数重载不能只有函数返回值类型不同
②main函数不能重载
2.2 🚝演示
比如下面我们定义几个Print函数:
这些函数接受的形参类型不一样,但是执行的操作类似。功能相同
当调用这些函数时,编译器会根据传递的实参类型 推断想要的是哪个函数:
👉函数的名字仅仅是让编译器知道它调用的是哪个函数
而函数重载可以在一定程度上减轻程序员给函数起名字、记名字的负担。
2.3 🚝用法注意事项
a) 不能只有返回值类型不同
b) 类型顺序相同,形参名字不同不构成函数重载
要求类型的顺序不同,不是形参名字的顺序
比如:
到底应该调用哪一个?
无法确定!
会产生歧义
c) 相同类型数据,顺序不同不构成函数重载
与b)类似
b)、c)归结起来就是:形参的名字仅仅起到帮助记忆的作用,有没有它并不影响形参列表的内容
像这样不写形参的名字也是编的过的:
2.4🚝 const 形参
顶层const不影响传入函数的对象。
一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开来
比如:
①
第二行重复声明了int Add(int a);
②
第6行重复声明了int Add(int* a);
在这两组函数声明中,每一组的第二个声明和第一个声明是等价的
三、引用🛫
3.1🚝 什么是引用
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
引用即别名:引用并非对象,相反的,它只是为一个已经存在的 对象所起的另外一个名字
语法:类型& 引用变量名(对象名) = 引用实体
📘例如:
int a = 10;
int& b = a;
通过调试观察引用跟原来变量的关系↓
➡印证了概念中所说的:编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
3.2 🚝引用的定义
允许在一条语句中定义多个引用,其中每个引用标识符都必须以&
开头
int main()
{
int i = 1024, i2 = 2048;//i和j都是int
int& r = i, r2 = i2;//r是引用,与i绑定;r2是int
int i3 = 1024, &ri = i3;//i3是int;ri是引用,与i3绑定
int& r3 = i3, & r4 = i2;//r3\r4都是引用
return 0;
}
3.3🚝 特性
a. 在定义时必须初始化
一般在初始化变量的时候,初始值会被拷贝到新建的对象中。But,定义引用时,程序把引用和它的初始值绑定在一起, 而不是将初始值拷贝给引用。
👉👉👉因此,一旦初始化完成,引用就跟它的初始值对象一直绑定在一起,以后就再也分不开了(即无法让这个引用绑定另一个对象了~),故引用必须初始化!
b. 引用类型的初始值必须是一个对象(不能是常量)
除了两种例外情况,其他所有引用的类型都要和与之绑定的对象严格匹配。What’s more,引用只能绑定在对象上 ,不能与字面值 or 某个表达式的计算结果绑定在一起
c. 一个变量可以有多个引用
通俗一点来说,别名可以不只有一个。
就好比孙悟空的别名有孙行者、心猿、金公、斗战胜佛、齐天大圣等等
对别名取别名也是允许的,例子见《4.1 什么是引用》的第一张图
d. 一旦引用一个实体,再不能引用其他实体
b = x
就只是赋值而已,b绑定的仍是a(并不是让 b 变成 x 的别名)
3.4🚝 常引用
a. const 修饰的常变量
const int a = 10;
int& ra = a;
const int& cra = a;//正确
加了const
限定,使得 a
不能被修改(权限为“ 只读 ”),那么a
的引用也不可以被修改。a
权限是只读,但是引用 ra
没有加const
修饰,权限为“ 可读可写 ”(a的引用权限放大了,会报错)
所以可以使ra
的权限变成和 a
相同的,即加上 const
修饰 ra
(见上图),就可以消除这个error了
b. 常量
int& b = 10; // 该语句编译时会出错,b为常量
const int& rb = 10;//正确
解释跟a. const 修饰的常变量
类似
c. 不同类型
double d = 12.34;
int& rd = d; // 该语句编译时会出错,类型不同
const int& rd = d;//会给出警告,但不是error
double变int会丢失精度
3.5🚝 引用与指针的区别
在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
这里我们不需要理解引用底层的实现(引用的底层其实也是用指针实现的)
只明确引用不开辟空间就行了
引用和指针的不同点:
-
- 引用概念上定义一个变量的别名,指针存储一个变量地址。
-
- 引用在定义时必须初始化,指针没有要求
-
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
-
- 没有NULL引用,但有NULL指针
-
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
-
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
-
- 有多级指针,但是没有多级引用
-
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
-
- 引用比指针使用起来相对更安全