CPP相较于C语言增加了很多新的概念,本篇博客将和大家一起学习CPP中函数的缺省参数以及函数重载。
相信跟着本篇博客学习完后你对CPP会有更深一层的理解。
一、缺省参数
1.1. 缺省参数的概念
缺省参数在CPP中是一个新的概念,那么什么是缺省参数呢?
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
| 例 |
#include <iostream>
void Func(int a = 10)
{
std::cout << a << std::endl;
}
int main()
{
Func(); // 没有传参,使用函数中给定的缺省值
Func(20); // 有传参,使用指定的实参
return 0;
}
1.2. 缺省参数的分类
● 全缺省参数
void Func(int a = 10, int b = 20, int c = 30) // 给所有的参数都指定缺省值
{
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
std::cout << "c = " << c << std::endl;
}
● 半缺省参数 (部分缺省参数)
void Func(int a, int b = 20, int c = 30) // 给部分参数指定缺省值
{
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
std::cout << "c = " << c << std::endl;
}
1.3. 有关缺省参数的注意事项
ⅰ半缺省参数必须从右往左依次给参数指定缺省值,不能间隔参数给缺省值
void Func(int a, int b = 10, int c) // (error)
{
// ...
}
若只想让形参b缺省参数形参c不缺省,可以:
void Func(int a, int c, int b = 10) // 交换形参b和形参c的位置即可
{
// ...
}
ⅱ 缺省参数不能在函数声明和定义中同时出现
( 如果函数的声明与定义位置同时出现缺省参数,恰巧两个位置提供的缺省值不同,那编译器就无法确定到底该用哪个缺省值。)
ⅲ 调用函数时传部分参数,默认只能从左往右依次传给各个形参,不可跳跃传参
void Func(int a = 10, int b = 20, int c = 30)
{
// ...
}
int main()
{
Func(); // (✔) a = 10,b = 20,c = 30
Func(1); // (✔) a = 1,b = 20,c = 30
Func(1, 2); // (✔) a = 1,b = 2,c = 30
Func(1, 2, 3); // (✔) a = 1,b = 2,c = 3
Func(1, , 2); // (✘) 不可跳跃传参
return 0;
}
ⅳ 调用半缺省参数的函数时,不能不传参
void Func(int a, int b = 20, int c = 30) // 半缺省参数
{
// ...
}
int main()
{
Func(1); // (✔) a = 1,b = 20,c = 30
Func(1, 2); // (✔) a = 1,b = 2,c = 30
Func(1, 2, 3); // (✔) a = 1,b = 2,c = 3
Func(); // (✘) a = ? 不能不传参数
return 0;
}
ⅴ 缺省值必须是常量或者全局变量 (使用全局变量作为缺省值的情况较少)
ⅵ C语言不支持 (编译器不支持)
二、函数重载
在自然语言中一个词被赋予了多重含义,就可以认为这个词被重载了。例如奇葩就是一个重载词,需要通过上下文的语境去判断它所表达的意思。
2.1. 函数重载的概念
函数重载是函数的一种特殊情况,CPP允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表 (参数个数或参数类型或参数类型顺序) 不同,常用来处理实现功能类似数据类型不同的问题。
● 参数个数不同
void f()
{
std::cout << "f()" << std::endl;
}
void f(int a)
{
std::cout << "f(int a)" << std::endl;
}
● 参数类型不同
int Add(int left, int right)
{
std::cout << "int Add(int left, int right)" << std::endl;
return left + right;
}
double Add(double left, double right)
{
std::cout << "double Add(double left, double right)" << std::endl;
return left + right;
}
● 参数类型顺序不同
void f(int a, char b)
{
std::cout << "f(int a,char b)" << std::endl;
}
void f(char b, int a)
{
std::cout << "f(char b, int a)" << std::endl;
}
2.2. CPP支持函数重载的原理 — 名字修饰 (name Mangling)
下面我们将在Linux环境下,采用g++对一段包含重载函数的代码进行编译。
经过g++编译后,int Func(int a,int b) 变成了 _Z4Funcii,double Func(double a,double b) 变成了 _Z4Funcdd。
到这里可以得出一个结论,在Linux环境下,经过g++编译函数名经过修饰后会转变成【_Z+函数名长度+函数名+形参类型首字母】的形式,函数的参数不同,修饰出来的名称就不同。正是因为有这样的函数名修饰规则,CPP中的函数重载才得以实现。
用一句话来概括来概括就是,CPP中函数重载的实现由函数名修饰规则来支撑。
结合上面的汇编代码再回顾刚刚函数重载的概念,思考一下,函数的返回值不同能否构成函数重载呢?
答案是不能构成函数重载!
有的小兄弟可能就会觉得是因为函数名修饰规则中没有把返回值类型加到函数名转变后的形式中,所以导致函数返回值类型不同不能构成函数重载。
首先这种想法是错误的,其次这种想法还是错误的。就算把函数返回值类型加到函数名转变后的形式中,函数返回值的类型不同还是无法构成函数重载。
函数返回值类型不同,不能构成函数重载的根本原因:
在调用函数时只能指定传递的实参的类型,而无法指定函数的返回值类型,此时就产生了二义性,编译器无法判断你要调用的是哪一个函数。
以上面这段代码为例,两个Func函数的形参都是int类型,当我们在调用Func函数时,无法指定Func函数的返回值类型,传的实参是1和2,两个实参都是int类型,这两个Func函数都能接收我们所传递的参数,此时编译器就无法判断要调用哪个Func函数了。
三、缺省参数与函数重载的结合
通过上文的学习,对CPP中缺少参数和函数重载有了一定的了解,思考一下,以下这两个函数构成函数重载吗?
void Func()
{
// ...
}
void Func(int a = 10, int b = 20)
{
// ...
}
程序执行成功,显然这两个函数是构成函数重载的。
但是在调用类似这种重载函数时,我们需要非常小心,不然稍不留神就会编译报错了。
void Func()
{
// ...
}
void Func(int a = 10, int b = 20)
{
// ...
}
int main()
{
Func(1); // (✔)
Func(1, 2); // (✔)
Func(); // (✘) 对重载函数调用不明确
return 0;
}
重点解释第三种函数调用:
以上两个函数构成函数重载,在调用函数时不传实参,能够调用上面的Func函数,也能够调用下面的Func函数(形参使用指定的缺省值),此时就产生了二义性,编译器无法判断你要调用的是哪一个Func函数。
本次与大家一起学习CPP中函数的缺省参数以及函数重载到这就已经接近尾声了,期待下次与你相遇。
< 你的关注,点赞,评论,收藏都是对我创作最大的鼓励 >
( 若本篇博客存在错误,望指出,感谢! )