目录
函数重载就是在满足一定的条件下定义的函数名可以相同,那需要什么条件呢?
- 同一个作用域下
- 函数名称相同
- 函数的参数类型不同或者个数不同或者顺序不同
1 重载发生的条件
1.1 函数参数类型不同
void Test01(int a)
{
std::cout <<"(int a)"<< a << std::endl;
}
void Test01(double a)
{
std::cout <<"(double a)"<< a << std::endl;
}
1.2 函数参数个数不同
void Test01(int a)
{
std::cout <<"(int a)"<< a << std::endl;
}
void Test01(int a, int b)
{
std::cout <<"(int a, int b)"<< a << b << std::endl;
}
1.3 函数参数顺序不同
void Test01(double b, int a)
{
std::cout <<"(double b, int a)"<< a << b << std::endl;
}
void Test01(int a, double b)
{
std::cout <<"(int a, double b)"<< a << b << std::endl;
}
注意!函数的返回值不能作为函数重载的条件
1.4 函数重载的注意事项
引用作为函数重载
重载函数中有默认值
1.4.1 引用作为函数重载的条件
void Test01(int& b)
{
std::cout << "(int& b)" << std::endl;
}
void Test01(int b)
{
std::cout << "(int& b)" << std::endl;
}
int main()
{
int a = 20;
Test01(a);
return 0;
}
上面两个函数是不是构成了重载,我们分析一下,是不是变量a既可以传给引用,也可以直接赋值,这让没我们聪明的编译器该如何选择呢?编译器傻了不知道该调用哪一个了,所以编译器报错。
所以我们在实际工程时候一定要避免这样的写法。避免产生二义性。
1.4.2 函数重载碰到默认参数
void Test01(int b = 10)
{
std::cout << "(int b = 10)" << std::endl;
}
void Test01()
{
std::cout << "( )" << std::endl;
}
int main()
{
Test01();
return 0;
}
这个代码,应该调用哪一个呢?上面给了一个默认参数,如果函数调用的时候不给那么就用默认参数,但是下面又写了一个不需要传参的,两个函数都不需要传参就可以进行调用,那么编译器选择调用哪个呢?编译器没选择,编译器只能报错。
所以我们在写重载函数的时候尽量避免使用默认参数,或者使用的时候小心一点,避免给自己挖坑。
2 函数重载的底层原理
2.1 C语言函数名修饰规则
C语言的函数名修饰规则非常简单,直接使用函数名就行查找
2.2 C++函数名修饰规则
//f.h
#include<iostream>
#include<stdio.h>
void f(int a, double b);
void f(double d, int a);
//f.cpp
void f(int a,double b)
{
printf("%d,%f\n",a, b);
}
void f(double d, int a)
{
printf("%d,%f\n", b, a);
}
//test.cpp
#include"f.h"
int main()
{
f(1, 2.222);
f(2.222, 1);
}
我们通过Linux使用g++编译出汇编代码,看一下函数名的修饰规则,
我们发现void f(int a, double b);函数被修饰成_Z1fid
void f(double d, int a);函数被修饰成_Z1fdi
- -Z:是一个标识
- 1:代表函数名的长度
- f:代表函数名称
- d:表示double类型的简写,表示这个位置上是一个double类型的参数
- i:表示int类型的简写,表示这个位置上是一个int类型的参数
我们根据上面的修饰规则,更加清楚的明白为什么,函数参数的个数不同或者函数参数的类型不同或者函数参数的顺序不同都可以发生重载的原因。