紫砂了紫砂了

函数的东西一堆堆,还涉及到栈,但是只是单纯的知识层面没法结合实际去玩就很恼。。。大概这就是没天赋吧,看后面有没有什么例子补救补救的


正文

在C语言里,函数名是不能重复的,变量也是[咱不提全局和局部]。
而在c++里,有函数重载的方法,可以让一个函数名有多个功能。

要实现自定义函数完成两个数或者多个数的平均值时:

1
2
3
4
5
6
7
int Ave(int a, int b){
return (a + b) / 2;
}
int Ave1(int a, int b, int c){
return (a + b + c) / 3;
}

其实变化不大,但是要额外定义。所以c++的函数就多了重载的功能:

1
2
3
4
5
6
int Ave(int a, int b){
return (a + b) / 2;
}
int Ave(int a, int b, int c){
return (a + b + c) / 3;
}

函数可以用相同的名称,因为功能大致接近很好的提示了可用性

编译器也会提示有两个重载方法

至于形参的提示可能头一回两个没缓过来吧。问题不大。

牛逼的是他甚至可以越过类型:
结果也正常显示:

以至于其实改变函数内部的写法也没啥关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>

int Ave(int a, int b){
return (a + b) / 2;
}
int Ave(int a, int b, int c){
return (a + b + c) * 3;
}
float Ave(float a, float b, float c){
return (a + b + c) / 3;
}

int main(){
std::cout << Ave(5, 10) << std::endl;
std::cout << Ave(5, 10,20) << std::endl;
std::cout << Ave(2.0f, 5.0f,10.0f);

return 0;
}

在返回值不一样的情况下调用,依旧能够分清谁是谁:

函数重载的时候首先肯定是对照函数名,然后形参个数,再然后形参类型

当然不会有绝对的好事
比如当实际参数比预期参数少的时候,不同类型的形参又会进行转换。
例如:
实际上参数类型是float,但是由于形参个数对不上,就只能找到两个int形参的函数。


内容不一致

1
2
3
4
5
6
int Ave(int a, int b){
return (a + b) / 2;
}
int Ave(int a, int b){
return (a + b) / 4;
}

两个函数不管是名字还是参数都一样,但是函数内容不一样的时候,编译器也不能保证调用的时候给你匹配哪一个。

所以说区分相同的函数,原则上只能比较形参,即使改变返回值类型也不能改变程序知道该匹配哪个函数的问题


形参为指针或数组

哦差点忘了指针和数组的时候:

1
2
3
4
5
6
int Ave(int *p, int count){
return 0;
}
int Ave(int p[], int count){
return 0;
}

虽然我们强调数组的本质是指针,但是类型来讲数组就是数组,指针就是指针,在形参表达上它们是不一样的。所以此处也是无法实现函数重载的。


形参为引用

然后还有c++的特点-引用:

1
2
3
4
5
6
int Ave(int& a, int& b){
return (a + b) / 2;
}
int Ave(int a, int b){
return (a + b) / 2;
}

在编译的时候肯定没啥问题,但是在使用中就会有歧义
例如我们之前打印的时候用的都是临时变量,临时的变量没有明确的地址,就不会存在引用的功能,所以不会匹配到上面那个参数是引用的重载。
但是如果传递了两个变量,语法就出现了歧义,因为他都能适配,但是不知道该调用哪个


引用和浮点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int Ave(int& a, int& b){
return (a + b) / 2;
}

float Ave(int a, int b){
return (a + b) / 2;
}
int main(){
char a = 100;
char b = 200;
std::cout << Ave(a,b) << std::endl;

return 0;
}

打印肯定是没问题的,但是a和b在传参的时候会进行隐转,毕竟类型不一样

可以看到它使用的是float类型的重载,但是按道理他是变量,为啥没匹配上面的引用,如果将进行强制转换成int会不会匹配引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int Ave(int& a, int& b){
return (a + b) / 2;
}

float Ave(int a, int b){
return (a + b) / 2;
}
int main(){
char a = 100;
char b = 200;
std::cout << Ave((int)a,(int)b) << std::endl;

return 0;
}

但是显然没有匹配引用。这就不得不提到强转的问题,a原本是char类型的变量,但是强转之后的值是一个临时产物,也就是临时变量,在上面我们就说过,临时变量的地址不固定,所以他不会有引用的选项。


常量形参

1
2
3
4
5
6
int Ave(int a, int b){
return (a + b) / 2;
}
int Ave(const int a, const int b){
return (a + b) / 2;
}

当参数为const限定时,函数还会重载吗。
答案也是不会。在进行模拟swap函数的时候就该知道,想要通过函数传参去改变变量原有的值,只能通过指针或者引用。

所以形参a和b或者const之后的a和b,其实本质上都不会对原有值发生改变,所以编译器又傻了,又出现了歧义。


常量引用

1
2
3
4
5
6
int Ave(int &a, int &b){
return (a + b) / 2;
}
int Ave(const int &a, const int &b){
return (a + b) / 2;
}

上面提到的语义是因为函数不会改变形参的值,所以const有没有限定和编译器要不要用就产生了分歧.
那如果设置了引用和常量引用,编译器是否能分期:

答案是能,因为const就是常量,引用重载的时候要么能改变要么不能改变,这里编译器自己肯定能分清。


默认参数

回顾函数的形参种类,有一种默认参数

1
2
3
4
5
6
int Ave(int a=150, int b=250){
return (a + b) / 2;
}
int Ave(float a=300.0f, int b=200.0f){
return (a + b) / 2;
}

有默认参数的好处是调用函数的时候,不需要给形参传递函数也能用。
但是Ave()的时候。。编译器又傻了,他就不知道该调用哪个了,又产生了歧义。
所以默认参数的函数也不能重载。


结语

。。切记有些特性属于c++的,不要和C语言弄混了,这里的重载就是c++的特性之一
当然特性归特性,无非也就是委员会提前制定的标准,c语言的精华就是造轮子,等哪天自己能造了技术也迈开一大步了