· CSDN的uu们,大家好。这里是C++入门的第三讲。
· 座右铭:前路坎坷,披荆斩棘,扶摇直上。
· 博客主页: @姬如祎
· 收录专栏:C++专题
目录
1. 知识引入
2. 缺省参数知识点
2.1 全缺省
2.2 半缺省
2.3 函数定义给缺省值还是函数声明给缺省值
2.4 小小的补充
1. 知识引入
还记得我们在用C语言实现栈的时候不是给了一个默认的栈的大小吗?当时我们使用的是#define定义标识符,然后初始化栈的时候,我们就会使用这个默认的标识符来初始化栈的大小。
#define STACK_INIT_SIZE 4
struct Stack
{
int* a;
int size;
int capacity;
};
void StackInit(struct Stack* st)
{
assert(st);
st->a = (int*)malloc(sizeof(int) * STACK_INIT_SIZE);
if (st->a == NULL)
{
perror("StackInit::malloc");
exit(-1);
}
st->size = 0;
st->capacity = STACK_INIT_SIZE;
}
我们可以看到这个代码有一个明显的缺陷,就是如果说我们一旦指定了 STACK_INIT_SIZE 的大小之后,后续就无法进行更改了。一旦我们想创建不同初始大小的栈,C语言的这种写法就无法满足我们的需求。因此C++引入了缺省参数的概念。
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
我们先来看有了缺省参数的好处:有了缺省参数,在调用StackInit函数时我们可以不传参,默认开辟4个大小的空间。也可以指定串defaultCapacity,这样就可以实现栈不同的初始大小。
struct Stack
{
int* a;
int size;
int capacity;
};
void StackInit(struct Stack* st, int defaultCapacity = 4)
{
assert(st);
st->a = (int*)malloc(sizeof(int) * defaultCapacity);
if (st->a == NULL)
{
perror("StackInit::malloc");
exit(-1);
}
st->size = 0;
st->capacity = defaultCapacity;
}
int main()
{
struct Stack st1;
StackInit(&st1); //创建一个初始大小为4的栈
struct Stack st2;
StackInit(&st2, 100); //创建一个初始大小为100的栈
return 0;
}
2. 缺省参数知识点
再来看看缺省参数的定义:
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
2.1 全缺省
我们会想,可以把函数的参数全部都设置一个缺省值吗?当然是可以的哦!我们称之为全缺省。
void func(int a = 10, int b = 20, int c = 30)
{
cout << a << " " << b << " " << c << endl;
}
int main()
{
func();
func(1);
func(1, 2);
func(1, 2, 3);
}
既然是全缺省,就会上面这么多种调用函数的方式。
但是,这里我就想发问了:我们部分传参的时候,实参与形参的匹配顺序是怎样的呢?
比如:func(1, 2) 的输出结果是什么呢?答案是:1 2 30 。实参会从左向右去与形参进行匹配。
2.2 半缺省
所谓的半缺省就是,只有一部分参数是给了缺省值的。比如下面的代码:
void func(int a, int b = 20, int c = 30)
{
cout << a << " " << b << " " << c << endl;
}
int main()
{
func(1);
func(1, 2);
func(1, 2, 3);
}
上面在全缺省是我们提到了:实参会从左向右依次去匹配形参。那么我们就能够得出结论:半缺省参数必须从右往左依次来给出,不能间隔着给。
2.3 函数定义给缺省值还是函数声明给缺省值
这里我想发问了:为什么不能函数声明与定义同时给缺省值呢?我们来看下面的代码:
我们将函数定义与函数声明的缺省值设置为不同的常量。
void func(int a = 10); //函数声明
void func(int a = 20) //函数定义
{
cout << a << " " << endl;
}
int main()
{
func();
return 0;
}
运行之后会报错:
你在函数定义与函数声明同时给缺省值,缺省值不一样的时候它到底听谁的呢?还有就是就算缺省值一样,编译也不能通过,(VS2019)编译器已经禁止了这种行为。
那到底是函数定义给,还是函数声明给呢?这就得联系编译链接的知识了。
我们将函数的定义与函数的声明分文件编写,先看看代码:
/
//test.h 中的代码
void func(int a = 20); //函数的声明
//test.cpp中的的代码
void func(int a) //函数的定义
{
cout << a << endl;
}
//main.cpp 中的代码
#include "test.h"
#include<iostream>
using namespace std;
int main()
{
func();
return 0;
}
这里的结论就是,缺省值需要在定义给。编译链接大致分为预处理,编译,汇编,链接四个阶段。在预处理阶段,主要执行头文件的展开,宏的替换,条件语句的确定······,然后头文件就不会存在了。每个源文件会分别,各自编译。在main.cpp编译时,经过预处理阶段头文件的展开,在main.cpp中就会有func函数的声明:void func(int a = 20); 在main函数调用 func() 处,编译器就会将这条语句理解为 func(20),那么main.cpp的编译就没有问题。
如果我们是在函数的定义里面给缺省值,那么在main.cpp编译过程中,函数的定义就会是这样的:void func(int a),在main函数调用 func() 处就会报错:func()不接受0个参数,即无法编译成功。
这里的C2660中的C就是英文单词Compile (编译) 的缩写,即编译阶段报的错误。
因此,我们可以得出结论:缺省参数能且只能在函数声明的时候给。
2.4 小小的补充
函数形参的缺省值可以是全局变量,也可以是常量。
int global = 20;
void func(int a, int b = global, int c = 30)
{
cout << a << " " << b << " " << c << endl;
}