【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++

 

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_缺省参数_02

💭 写在前面

本章将带领大伙学习C++的缺省参数和函数重载部分的知识。对于一些容易出错的地方,我会帮大家踩坑演示一波。


Ⅰ. 缺省参数

0x00 引入

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++_03

💬 这是一个简单的函数,功能就是打印出传递过来的数字:

#include <iostream>
using namespace std;

void Func(int num) { // 此时接收,num = 1
cout << num << endl;
}

int main(void)
{
Func(1); // 传参:1

return 0;
}

🚩 运行结果: 1

❓ 如果我不想传参呢?我想直接调用 Func

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_缺省参数_04

#include <iostream>
using namespace std;

void Func(int a) {
cout << a << endl;
}

int main(void)
{
Func();

return 0;
}

🚩 运行结果:(报错)

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_ios_05

💡 因为没有传递参数,所以自然会引发报错。

不过,在C++里我们可以利用一个叫 "缺省参数" 的东西,让该函数可以做到不传参也能运行的效果。

💬 利用 "缺省参数" :

#include <iostream>
using namespace std;

void Func(int a = 0) {
cout << a << endl;
}

int main(void)
{
Func();

return 0;
}

🚩 运行结果:(成功)

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_#include_06

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_缺省参数_07

 居然还能这么玩?下面我们就将学习这个神奇的 "缺省参数" 。

0x01 基本概念

神奇的 C++ 提供了缺省参数。

❓ 缺省参数,缺省……什么是缺省参数?

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++_08

 说人话就是 —— 默认参数!!!

【百度百科】缺省,即系统默认状态,意思与“默认”相同。

📚 缺省参数:声明函数或定义函数时为函数的参数指定一个默认值。

该函数在调用时,如果没有指定实参,则采用该默认值;否则使用指定的实参。

简单来说就是:传参了就用传来的值,没传参就用默认值。

0x02 缺省参数的用法

💬 代码演示:

#include <iostream>
using namespace std;

void Func(int a = 0) { // 缺省值作为形参,传给 a
cout << a << endl;
}

int main(void)
{
Func(10); // 传参时:使用指定的实参(传入10)
Func(); // 没有传参时,使用默认的参数值(默认值:0)。

return 0;
}

🚩 运行结果如下:

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_#include_09

🔑 解析:

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_ios_10

① 第一次调用 Func 时,指定了实参,就会照常传入,这里指定的是 10,所以传过去的是 10

② 第二次调用 Func 时,并没有指定实参,所以进入函数后,形参 a 会取缺省值 0 作为参数的值。

③ 因此,第一次打印的结果是 10,第二次打印的结果是 0

📌 注意:

① 声明不能在 .h 和 .cpp 里同时出现缺省参数,要么申明里写,要么在定义里写!

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_#include_11

② 缺省值必须是常量或全局变量。

② 缺省参数C++里面的,C语言不支持(编译器不支持)。

0x03 缺省参数的分类

📚 缺省参数分为 全缺省参数半缺省参数

① 全缺省参数:函数中的所有参数都给了缺省值。

② 半缺省参数:函数中的所有参数从右往左给一部分的缺省值。

0x04 全缺省参数

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_缺省参数_12

📚 必须所有参数都带有缺省值,才能叫作全缺省参数。

💬 代码演示:

#include <iostream>
using namespace std;

void Func(int a = 10, int b = 20, int c = 30) {
printf("%d %d %d\n", a, b, c);
}

int main(void)
{
Func(); // 不穿,一个都没传
Func(1); // 只传了一个
Func(1, 2); // 传了两个,但没完全传
Func(1, 2, 3); // 全都传了,就没缺省参数什么事了

return 0;
}

🚩 运行结果如下:

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++_13

🔑 解析:

① 第一次调用 Func

② 第二次调用 Func

③ 第三次调用 Func

④ 最后一次调用 Func

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_#include_14

#include <iostream>
using namespace std;

void Func(int a = 10, int b = 20, int c = 30) {
printf("%d %d %d\n", a, b, c);
}

int main(void)
{
Func(, 2,);

return 0;
}

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_ios_15

❌ 不可以!只传 b

参数的传递按照语法是从左往右传递的,因为这是语法定死的,所以没有办法传。

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_#include_16

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++_17

 其实也并不是那么绝对的!在 C++11

0x04 半缺省参数 

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_缺省参数_18

📚 半缺省参数:函数中的所有参数从右往左连续地缺省一部分

这一部分可以是多个参数,也可以是一个参数(一个也算一部分),

但是它们必须是 "连续地" 。参数传递顺序根据根据函数调用约定。

📌 注意事项:

① 半缺省并不是缺省一半,而是缺省一部分。

② 半缺省参数必须从右往左缺省,且必须是连续地。即,必须从右往左连续缺省。

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++_19

这是规定!这是大佬规定的!不服?

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++_20

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_#include_21

吐槽:既然不是缺省一半,还叫半缺省参数,这合理吗?这不合理!

这个 "半" 字确实用的不合理,倒不如叫 "部分缺省参数" ,会显得更加合理一些。

💬 代码演示:

#include <iostream>
using namespace std;

// 👈 从左往右 "连续地"
void Func(int a, int b, int c = 30) {
printf("%d %d %d\n", a, b, c);
}
/* 半缺省:从右往左连续地缺省一部分参数
a - 必须传 (因为没缺省)
b - 必须传 (因为没缺省)
c - 可传可不传 (因为缺省了)
*/

int main(void)
{
Func(1, 2); // a b 没缺省,所以必须要传,c缺省了所以可以不传
Func(1, 2, 3); // 都传

return 0;
}

🚩 运行结果如下:

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++_22

📜 建议:既然大佬是这么设计的,那我们也没办法。所以为了迎合这个特性,设计函数的时候如果有参数是必须要传递的,就放到前面;不是必须要传的,可以放到后面(制作成缺省参数)。

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++_23

0x05 缺省参数的应用场景

📚 缺省参数的运用场景有很多,我们随便举个例子。

我们在学习数据结构时,实现顺序表、栈时定义容量 capacity 时,默认值我们当时推荐的是给 4,这里就可以设置缺省值:

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_缺省参数_24

💬 演示(仅展示部分代码):

typedef struct Stack {
int* array;
int top;
int capacity;
} Stack;

void StackInit (
Stack* pst,
int capacity = 4 // 设置缺省值为4(默认容量为4)
)
{
pst->array = (int*)malloc(sizeof(int) * capacity);
pst->top = 0;
pst->capacity = capacity;
}


int main()
{
Stack st;
StackInit(&st); // 不知道栈最多存多少数据,就用缺省值初始化
StackInit(&st, 100); // 知道栈最多存100数据,显示传值。这样可以减少增容次数。

return 0;
}

这么一来,就不需要考虑增容的概念了,这就是缺省参数的好处。所以,这个特性确实是很有用的,可以让我们更方便。

Ⅱ. 函数重载

0x00 引入

自然语言中,同一句话,可能有多重意思,人们可以通过上下文来判断这句话的真实的含义:

国有两大体育项目不用看,也不用担心。一个是乒乓球,一个是国足。前者是 "谁也赢不了" ,后者是 "谁也赢不了" 。

"谁也赢不了" ,就相当于被重载了。

0x01 函数重载的概念

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_缺省参数_25

📚 函数重载:C++ 允许在同一个作用域中存在同名的函数。

下面三个不同只要满足一个不同,就可以触发函数重载:

① 参数类型不同

② 参数个数不同

③ 参数顺序不同

0x02 函数重载的三种不同

参数类型不同

💬 代码演示:

#include <iostream>
using namespace std;

int Add(int x, int y) {
cout << "int x, int y" << endl; // 为了方便区分
return x + y;
}

double Add(double x, double y) {
cout << "double x, double y" << endl; // 为了方便区分
return x + y;
}

int main(void)
{
cout << Add(1, 2) << endl;
cout << Add(1.1, 2.2) << endl;

return 0;
}

🚩 运行结果如下:

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++_26

参数个数不同

💬 代码演示:

#include <iostream>
using namespace std;

void Func(int a) {
cout << "Func(int a)" << endl;
}

void Func(char b, int a) {
cout << "Func(char b, int a)" << endl;
}
int main(void)
{
Func(10);
Func('A', 20);

return 0;
}

 🚩 运行结果演示:

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_#include_27

参数顺序不同

#include <iostream>
using namespace std;

void Func(int a, char b) {
cout << "int a, char b" << endl;
}

void Func(char b, int a) {
cout << "char b, int a" << endl;
}

int main(void)
{
Func(10, 'A');
Func('A', 10);

return 0;
}

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_ios_28

0x03 不支持函数重载的情况

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_#include_29

❌ 返回值不同,调用时无法区分:

#include <iostream>
using namespace std;

int foo(double d) {
;
}

void foo(double d) {
;
}


int main(void)
{
foo(1.1); // ??? 会不知道这里到底是进 int foo 还是 void foo

return 0;
}

🚩 运行结果:(报错)

函数重载不能依靠返回值的不同来构成重载,因为调用时无法根据参数列表确定调用哪个重载函数。

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_缺省参数_30

  

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_缺省参数_31

缺省值不同,不能构成重载!

#include <iostream>
using namespace std;
void foo(int a) {
cout << "foo(int a)" << endl;
}

void foo(int a = 10) {
cout << "foo(int a)" << endl;
}

int main(void)
{
foo(1);

return 0;
}

🚩 运行结果:(报错)

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_缺省参数_32

❎ 可构成重载但存在歧义,但使用时又是会出现问题:

#include <iostream>
using namespace std;

void func() {
cout << "func()" << endl;
}

void func(int a = 0) {
cout << "func(int a)" << endl;
}

int main(void)
{
func(); // 调用存在歧义 ❌
func(1); // 可以 ✅

return 0;
}

🚩 运行结果:(报错)

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_c++_33

 

【C++要笑着学】缺省参数 | 全缺省与半缺省 | 函数重载_ios_34


📌 [ 笔者 ]   王亦优
📃 [ 更新 ] 2022.1.22
❌ [ 勘误 ] qq_21049619:0X05示例代码的第22行写错了,
和21行重复了,应该是StackInit(&st, 100);【已修正】
PeppaZH:Ⅰ0x02 解析处打印结果写反了【已修正】
qq_15779857:0x05的例子第12行有误【已修正】
三都嗯:某处举例不合适【已修正】
📜 [ 声明 ] 由于作者水平有限,本文有错误和不准确之处在所难免,
本人也很想知道这些错误,恳望读者批评指正!

📜 参考资料 

Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

百度百科[EB/OL]. []. https://baike.baidu.com/.

比特科技. C++[EB/OL]. 2021[2021.8.31]. .