目录
函数的默认参数是指在定义函数参数的时候给它一个初始化的默认值,在函数调用的时候参数不足的情况下有一个缺省值,比如:
int func01(int a,int b,int c)
//这种就是没有默认参数的情况,在调用时必须传入三个参数给这个函数才能正常调用
{
return a+b+c;
}
在main中调用func01函数时,只传入了2个参数,与func01原定三个参数不一致,报错
若在调用时传入4个参数!=3个参数也会报错
只有传入参数个数与原定义函数参数一致时才不会报错
- #include
- using namespace std;
- int func01(int a, int b, int c)
- {
- return a + b + c;
- }
- int main()
- {
- int a = 10;
- int b = 20;
- int c = 30;
- int d = 40;
- cout << "func01=" << func01(a, b, c) << endl;
- system("pause");
- return 0;
- }
也能正常输出,输出结果是10+20+30=60的结果
int func02(int a = 1, int b = 1, int c = 3)
//函数的三个参数都给了默认值(也就是三个默认参数)
{
return a + b + c;
}
在调用时可以不传入任何新的参数直接func02()也可以正常执行输出,且输出结果是默认参数的相加结果1+2+3=6
- #include
- using namespace std;
- int func02(int a = 1, int b = 2, int c = 3)
- {
- return a + b + c;
- }
- int main()
- {
- int a = 10;
- int b = 20;
- int c = 30;
- cout << "func02=" << func02() << endl;
- system("pause");
- return 0;
- }
函数只有后两个参数b和c有默认值,而a没有
int func03(int a,int b=2,int c=3)//只有b和c有默认值,a没有
{
return a+b+c;
}
只有b和c默认参数,就意味着必须传入a所在位置的参数的值,也就是说在调用函数func03时必须至少传入一个参数,编译器会按照从左到右的顺序对应参数位置执行输出,而默认参数的读取顺序是从右->左(这就是后面3.2的注意事项的原因)
一个参数都不传入,就会出错,因为a不是默认参数
传入一个参数,按照从左到右,先填到a的位置
此时的输出结果是10+2+3=15
- #include
- using namespace std;
- int func03(int a, int b = 2, int c = 3)
- {
- return a + b + c;
- }
- int main()
- {
- int a = 10;
- int b = 20;
- int c = 30;
- cout << "func03=" << func03(a) << endl;
- system("pause");
- return 0;
- }
那么,在调用func03时传入a和b的值?
编译器会按照调用时传入的新参数值来代替原定义的默认参数值,默认参数值只是来替代没有传入参数的情况的默认处理
传入了a和b的值,输出结果是10+20+3=33
- #include
- using namespace std;
- int func03(int a, int b = 2, int c = 3)
- {
- return a + b + c;
- }
- int main()
- {
- int a = 10;
- int b = 20;
- int c = 30;
- cout << "func03=" << func03(a,b) << endl;
- system("pause");
- return 0;
- }
同理,传入三个参数,输出结果会是10+20+30=60
什么意思呢,也就是比如b给了默认值,在b的右边(之后的c)也必须是给了默认值的
b是默认参数,在b之后(右边的c不是默认参数,报错)
b,c都是默认参数,在bc后的d不是,也报错
实质原因是,编译器在读取函数默认参数是从右往左的顺序
函数声明时,已经给了参数以默认值,那么在定义时再次给同样的默认值就会出错
- #include
- using namespace std;
-
- int func04(int a = 1, int b = 2, int c = 3);//函数声明
- int func04(int a = 1, int b = 2, int c = 3)//函数定义
- {
- return a + b + c;
- }
-
- int main()
- {
- int a = 10;
- int b = 20;
- int c = 30;
- cout << func04() << endl;
- system("pause");
- return 0;
- }
光这么看着是没错的,运行之后就报了三个错误(看似人畜无害,实则藏得深呐)!
重定义了默认参数,函数声明的时候你定义了一次默认参数,函数定义的时候,又定义了一次默认参数,在main中就相当于
int main()
{
int a=1;
int b=2;
int c=3;
int a=1;
int b=2;
int c=3;
return 0;
}
重定义,多次初始化a,b,c
解决方法很简单,删掉函数声明或者函数定义中的其中一个的默认参数就行了
- int func04(int a, int b , int c );//删掉函数声明的默认参数
- int func04(int a = 1, int b = 2, int c = 3)//函数定义
- {
- return a + b + c;
- }
删掉函数定义的默认参数,也可以正常运行
- int func04(int a=1, int b=2 , int c =3);//函数声明
- int func04(int a , int b , int c)//删掉函数定义的默认参数
- {
- return a + b + c;
- }
那么,函数定义的默认参数值和函数声明里的不一样呢?
站在编译器的角度思考这个问题,那么,我编译器该执行你函数声明里的默认参数还是执行你函数定义里的默认参数呢?猜不透,直接罢工再给他报个错就好了(直接摆烂~)
- #include
- using namespace std;
-
- int func04(int a=1, int b=2 , int c =3);//函数声明
- int func04(int a=10 , int b=20 , int c=30)//删掉函数定义的默认参数
- {
- return a + b + c;
- }
-
- int main()
- {
- cout << func04() << endl;
- system("pause");
- return 0;
- }
报了一样的错,重定义默认参数(不得不说,编译器是真的懒得想新的错误解释)
所以呢,在定义函数参数时,默认参数不要少定义,函数声明和函数定义时,不要多定义
函数的占位参数,只有一个数据类型比如int,double,没有参数名 int b 少了b,只有一个孤零零的int
void func01(int a,int )//第二个参数只有一个数据类型连个参数名也没有,就是个占位参数
{
cout<<"this is func01"<
}
- #include
- using namespace std;
-
- void func01(int a, int)//一个参数a,一个没有名字的占位参数
- {
- cout << "this is func01" << endl;
- }
-
- int main()
- {
- func01(10);//在调用的时候忽略了占位参数,只传入了一个参数,报错
- system("pause");
- return 0;
- }
会报错,不能正常输出,因为忽略了占位参数的存在,函数调用中传入的参数太少,func01不接受一个参数
那么占位参数有默认参数么?
答案是跟普通参数一样有的,它除了没有名字,其他都跟普通参数一样
- #include
- using namespace std;
-
- void func01(int a, int =10)//一个参数a,一个没有名字的占位参数变成了默认参数,默认值是10
- {
- cout << "this is func01" << endl;
- }
-
- int main()
- {
- func01(10);//由于占位参数变成了默认参数,所以可以只传入一个非默认参数a的值,不会报错可以正常输出
- system("pause");
- return 0;
- }
1.1函数重载的作用:函数名可以相同,提高函数的复用性
1.2函数重载的满足条件:
- 同一个作用域下(同一个namespace 下,且在main函数之外的全局作用域)
- 函数名相同(name)
- 参数类型不同 或者 参数个数不同 或者 参数顺序不同(针对形参)
注意:函数的返回值不可以作为函数重载的条件
两个func名字一样,参数一样,作用域也一样,不属于函数重载的范畴,在函数调用时编译器不知道调用哪个,所以报错
- #include
- using namespace std;
-
- int func(int a, int b)//func名字一样,参数一样,作用域也一样,不属于函数重载的范畴
- {
- return a+b;
- }
-
- int func(int a, int b)//func
- {
- return a+b;
- }
- int main()
- {
- cout<<func(10,20)<
- system("pause");
- return 0;
- }
如果返回值不一样呢
一个return a+b;
一个return a-b;
结果还是会报错,因为返回值不作为函数重载的条件
函数的返回值类型也不可以作为函数重载的条件
#include
using namespace std;
double func(int a, double b)
//作用域相同(都在main之外的全局定义之中),函数名相同都叫func
{
return a + b;
}
int func(int a, double b)
//参数类型和个数相同且顺序相同,只是返回值类型不同一个double,一个int,但是不能作为函数重载的条件
{
return a-b;
}
int main()
{
//编译器会根据传入的参数的第一个数和第二个数的类型和从左到右排的位置
//但是函数返回值类型不能让他们成为函数重载,且编译器报错
cout << func(10, 20.1230) << endl;
system("pause");
return 0;
}
2.函数重载的基本语法
小标题1的两个代码满足了同一作用域和相同名称的要求,但是没有满足第三个条件:
参数类型不同 或者 参数个数不同 或者 参数顺序不同(针对形参)
所以在进行函数重载时,我们应该还要保证函数形参的类型不同(个数,顺序均相同情况下)
#include
using namespace std;
int func(int a, int b)
//func名字一样,作用域也一样,但参数类型不一样,这个是int 另一个是double
{
return a + b;
}
int func(double a, double b)
//参数顺序和个数相同但是类型不同,一个是int一个是double,可以运行
{
return a-b;
}
int main()
{
//编译器会根据传入的数据类型来选择调用哪个参数类型的函数重载
//这里的10,20是int整型,调用第一个返回值是a+b的
cout << func(10, 20) << endl;
system("pause");
return 0;
}
同理,函数参数类型相同&顺序相同的情况下,但是参数个数有差异也是可以算作正确的函数重载的
#include
using namespace std;
int func(int a, int b,int c)
//func名字一样,作用域也一样,但参数个数不一样,这个是a,b,c(三个参数)另一个是a,b(两个参数)
{
return a + b;
}
int func(int a, int b)
//参数顺序和类型相同但是个数不同,一个是3个参数一个是2个参数,可以运行
{
return a-b;
}
int main()
{
//编译器会根据传入的参数个数来选择调用哪个函数重载
//这里的10,20是2个参数,调用第二个两个形参的return a-b=10-20=-10
cout << func(10, 20) << endl;
system("pause");
return 0;
}
类型不变,个数不变,变顺序(不过为了调用的结果明显要更改一下,不能一个函数里的两个参数都是int)
#include
using namespace std;
int func(int a, double b)
{
return a + b;
}
int func(double b, int a)//参数类型和个数相同但是顺序不同,double b放前面和doub b放后面
{
return a-b;
}
int main()
{
//编译器会根据传入的参数的第一个数和第二个数的类型和从左到右排的位置
cout << func(10, 20.1230) << endl;//第一个是int类型的10,第二个是double类型的20.1230,所以编译器会自动匹配到第一个函数重载
//至于返回结果为什么是个整数30而不是30.1230呢,是因为func是int类型的函数,返回值自然也要是int类型的啦,去尾存整
//如果把func换成double类型的,那么返回值自然也就会是30.1230了
system("pause");
return 0;
}
3.函数重载的注意事项
3.1引用作为重载条件
当重载函数的参数是int & a 和const int & a时的调用方法的差异
#include
using namespace std;
void func01(int & a)//当调用时传入的是变量时,调用此函数重载,此处形参中的a作为main中的a的别名(别名和原名可以相同)
{
cout << "func01(int & a)的调用" << endl;
}
void func01(const int & a)//常量引用作为函数参数,当调用时传入的是一个字面数字就会调用此函数重载
{
cout << "func01(const int & a)的调用" << endl;
}
int main()
{
int a = 10;
func01(a);//调用时传入的a是func01形参a的原名
func01(10);//此处编译器判定出传入的是常量10,匹配调用const int & a作为参数的函数重载
system("pause");
return 0;
}
3.2函数重载碰到默认参数
如果函数重载中,形参有一个是默认参数,而调用时又只传入一个参数,那么编译器该调用一个参数的函数重载,还是调用两个参数(其中有一个参数是默认参数)的函数重载呢?
#include
using namespace std;
void func02(int a, int b = 10)
{
cout << "this is func02(int a,int b=10)的调用" << endl;
}
void func02(int a)
{
cout << "this is func02(int a)的调用" << endl;
}
int main()
{
func02(10);//此时编译器无法识别这一个参数的调用究竟是要调用哪个函数重载
func02(10, 20);//此时正确,明确告知编译器要调用有两个形参来接收我传入的实参的函数重载
system("pause");
return 0;
}
至于默认参数概念和用法,在本文的第一章节详细讲述过
编译器报错调用不明确,看下错的地方是一个参数的调用的部分,只有把那段代码,改成两个参数的调用才可以(或者注释掉也行)
所以,友情提示,在使用函数重载的时候尽量不要使用默认参数,现在代码少了容易发现,以后写老长串的代码,特别是分文件写的时候一旦报错就又得花不少时间改bug