函数重载
函数重载的意义
在实际开发中,有时候需要实现几个功能类似的函数,只是细节有所不同。
如交换两个变量的值,但这两种变量可以有多种类型,short, int, float等。
在C语言中,必须要设计出不同名的函数,其原型类似于:
void swap1(short *, short *);
void swap2(int *, int *);
void swap3(float *, float *);
但在C++中,这完全没有必要。
C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数重载(Function Overloading)。
借助重载,一个函数名可以有多种用途。
函数重载的概念
函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重
载函数。
重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的
污染,对于程序的可读性有很大的好处。
C++进行函数重载的实现原理叫名字改编(name mangling),具体的规则是:
- 必须在同一作用域内。
- 函数名称必须相同 。
- 参数列表必须不同(参数的类型不同、个数不同、顺序不同)。
- 函数的返回类型可以相同也可以不相同。仅仅返回类型不同不足以成为函数的重载。
**注:**C++向下兼容C时,未做函数的名字改编。
若想要将一段代码用C语言的方式进行编译,可以用extern “C”{ }
将其包起来,示例如下:
extern "C"
{
int add(int x, int y){
return x+y;
}
}//end of extern c
若想要将一段代码,既可以放在C语言的编译器中,又可以放在C++的编译器中,均使用C语言的方式进行编译,可以用如下方式书写:
//如下表示:若为C++的编译器,则进入ifdef内部,使用extern C,若为C语言的编译器,则直接编译,不进入ifdef内部。
//C++与C的混合编程
#ifdef _cplusplus
extern "C"
{
#endif
int add(int x, int y){
return x+y;
}
#ifdef _cplusplus
}//end of extern C
#endif
函数重载的原理
在编译生成目标文件(.o文件)时,对函数名字进行了改编。
在同一个作用域内,编译生成目标文件(.o文件)时,若函数名字相同,编译器会根据函数参数列表中的参数的类型、个数和顺序,对函数名进行改编。
0000000000000000 T _Z3 add i i (add函数,参数为int和int类型)
0000000000000014 T _Z3 add i i i
0000000000000030 T _Z3 add f f (add函数,参数为float和float类型)
000000000000004a T _Z3 add f f f (add函数,参数为float、float和float类型)
0000000000000000 T _Z3 add i i
0000000000000014 T _Z3 add i i i
Linux常用命令
# 编译add.cc使其生成一个add.o文件
g++ -c add.cc
# 查看add.o文件的数据结构符号表
nm add.o
默认参数
默认参数的意义
减少代码书写量,减轻工作量。
C++可以给函数定义默认参数值。通常,调用函数时,要为函数的每个参数给定对应的实参。
void func1(int x, int y);
void func1(int x, int y)
{
cout << "x = " << x << endl;
cout << "y = " << y << endl;
}
无论何时调用func1函数,都必须要给其传递两个参数。但C++可以给参数定义默认值,如果将func1函
数参数中的x定义成默认值0, y定义成默认值0,只需简单的将函数声明改成
void func1(int x = 0, int y = 0);
这样调用时,若不给参数传递实参,则func1函数会按指定的默认值进行工作。允许函数设置默认参数
值,是为了让编程简单,让编译器做更多的检查错误工作。
默认参数的使用
- 最好是在函数声明的时候就在参数列表里写上默认参数。
- 当一个函数既有声明又有定义时,只需要在其中一个中设置默认值即可。
- 如果函数声明时不写默认参数,而在函数定义时候写默认参数,那么调用函数就需要在函数定义了之后。若先调用后定义,在调用时编译器并不知道哪个参数设了默认值。
默认参数的顺序规定
如果一个函数中有多个默认参数,则形参分布中,默认参数应从右至左连续定义,否则会报错。
当调用函数时,只能向左匹配参数。如:
void func2(int a = 1, int b, int c = 0, int d);//error
void func2(int a, int b, int c = 0, int d = 0);//ok
若给某一参数设置了默认值,那么在参数表中其后所有的参数都必须也设置默认值,否则,由于函数调
用时可不列出已设置默认值的参数,编译器无法判断在调用时是否有参数遗漏。
默认参数与函数重载混合使用 可能造成二义性
默认参数可将一系列简单的重载函数合成为一个。例如:
void func3();
void func3(int x);
void func3(int x, int y);
//上面三个函数可以合成下面这一个
void func3(int x = 0, int y = 0);
如果一组重载函数(可能带有默认参数)都允许相同实参个数的调用,将会引起调用的二义性,使得编译时报错。
所以在函数重载时,要谨慎使用默认参数。
void func4(int);
void func4(int x, int y = 0);
void func4(int x = 0, int y = 0);