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

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

💭 写在前面


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


Ⅰ. 缺省参数


0x00 引入

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


#include <iostream>
using namespace std;
void Func(int num) {      // 此时接收,num = 1
    cout << num << endl;  
}
int main(void)
{
    Func(1);              // 传参:1
    return 0;
}

🚩 运行结果: 1


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


#include <iostream>
using namespace std;
void Func(int a) {
    cout << a << endl;
}
int main(void)
{
    Func();
    return 0;
}

🚩 运行结果:(报错)

bdacf267f1e8f80a92f815396dad1c70_eff9f84d0dde4eb9a02da55069d8bf6e.png


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


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


💬 利用 "缺省参数" :


#include <iostream>
using namespace std;
void Func(int a = 0) {
    cout << a << endl;
}
int main(void)
{
    Func();
    return 0;
}

🚩 运行结果:(成功)

35a289b503ea279e21ee62d90241b91b_e247b89b392a45868cd2c454f6bdea8a.png

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


0x01 基本概念

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


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

7a5c34b1b85042751d3efe71720dc142_e335d3126e43477c93a62e5f81576de9.png

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


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


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


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


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


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;
}

🚩 运行结果如下:


60704e3126f64f7c22c00720cbaad198_e912fed20a984551a512e69c89089a92.png


🔑 解析:

0f85748bdb8f94358761ca2a91b84d55_ea927717c80f4e8889acf73059da1ac2.png



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


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


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


📌 注意:


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

c3a6af5650c92c74b8cadded26c0471a_351818391e674e3fba5bf3804a6d5482.png


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


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


0x03 缺省参数的分类

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


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


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


0x04 全缺省参数


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


💬 代码演示:


#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;
}


🚩 运行结果如下:

4bb0fed4a49add6d0355e1d77fffeb97_3af784cd19044f2abf5c3c4483af907c.png

🔑 解析:


① 第一次调用 Func 时,什么都没有传,所以结果直接就采用默认值。


② 第二次调用 Func 时,只传了一个参数,那么结果只有 a 不是默认值。


③ 第三次调用 Func 时,传了两个参数,那么结果只有 c 会是默认值了。


④ 最后一次调用 Func 时,所有参数都传了,那么结果都不会是默认值。


#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;
}

❌ 不可以!只传 b 不好传!


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

3a19fefbb775eb0861ecc54c24b352c3_3c9248bf213741f6a8d66891474e346c.png

其实也并不是那么绝对的!在 C++11 以后,加了包装器以后是可以支持只传中间那个的,但是那个比较复杂,不适合在这里讲。


0x04 半缺省参数

054cac9b2c5d91e32c86e713d33710c4_fdc79766910d4742a705e2b6ba59d7c1.png

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


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


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


📌 注意事项:


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


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


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


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


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


💬 代码演示:


#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;
}


🚩 运行结果如下:

2e0c520b7611f4d4290f9154bf4cc68c_a3a3603b77354e12b7481649432d76ab.png

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


0x05 缺省参数的应用场景

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


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


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

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++ 允许在同一个作用域中存在同名的函数。


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


① 参数类型不同


② 参数个数不同


③ 参数顺序不同


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;
}

🚩 运行结果如下:

282a02e5ae92fe2212ff682ec85c9fc6_3c7a8346689646a2a75e6f21cba7e962.png

参数个数不同


💬 代码演示:


#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;
}

🚩 运行结果演示:

7dc928cd80d3441514a61178a43dd17f_60c9b55625a143dd8bbd1a18172651b7.png


参数顺序不同


#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;
}

b2627a708e4683cdec4d5106c31612d8_8a355e4455e94d53a406f2ef8dd47365.png


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


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


#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;
}

🚩 运行结果:(报错)


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

843760b05e17091bd94dbd7e942ebfbb_6105939dcf2549a5af6e6bb0e0afd2ef.png

 

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


#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;
}

🚩 运行结果:(报错)

0ab447c042f928dbe8930b971c15343c_af403957006e44afb8012cf4183fce9b.png


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


#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;
}

🚩 运行结果:(报错)

6fc666c23759b47d1ebdedbf196040b4_7f409fb46d11495d8ca87da1f742844b.png



 


相关文章
|
1月前
|
程序员 C语言 C++
C++入门(头文件,命名空间,作用域,输入输出流,引用,缺省参数,函数重载)
C++入门(头文件,命名空间,作用域,输入输出流,引用,缺省参数,函数重载)
|
1月前
|
Linux C语言 C++
C++之函数重载【详解】
C++之函数重载【详解】
|
3天前
|
编译器 程序员 C++
C++缺省参数
C++缺省参数
12 0
|
15天前
|
C语言 C++ 数据格式
【C++对于C语言的扩充】C++与C语言的联系,命名空间、C++中的输入输出以及缺省参数
【C++对于C语言的扩充】C++与C语言的联系,命名空间、C++中的输入输出以及缺省参数
|
3天前
|
编译器 C++
C++函数重载详解
C++函数重载详解
6 1
|
17天前
|
编译器 C语言 C++
【C++】C++入门第一课(c++关键字 | 命名空间 | c++输入输出 | 缺省参数)
【C++】C++入门第一课(c++关键字 | 命名空间 | c++输入输出 | 缺省参数)
|
27天前
|
编译器 C语言 C++
【C++】函数重载
【C++】函数重载
25 2
|
1月前
|
编译器 C++
C++函数重载
C++函数重载
|
1月前
|
存储 自然语言处理 编译器
『C++成长记』C++入门—— 函数重载&引用
『C++成长记』C++入门—— 函数重载&引用
|
1月前
|
Unix 编译器 C语言
『C++成长记』C++入门——命名空间&缺省参数
『C++成长记』C++入门——命名空间&缺省参数