C++函数重载详解

C++重载函数其实是一种特殊的函数。它满足以下性质:

1,同一作用域

2,函数名相同

3,参数列表不同(参数个数,参数类型,参数顺序)


定义重载函数
例子:

有一种典型的数据库应用,需要创建几个不同的函数分别根据账户号码、名字、电话等信息查找记录。

函数重载使得我们可以定义以下一组函数,它们的名字都是lookup,但是查找的依据不用。

Record lookup(const Account&); //根据Account查找记录
Record lookup(const Name&);//根据Name查找记录
Record lookup(const Phone&);//根据Phone查找记录

Account acct;
Name name;
Phone phone;

Record r1 = lookup(acct);	//调用接受Account的版本
Record r2 = lookup(name);	//调用接受Name的版本
Record r3 = lookup(phone); //调用接受Phone的版本
解析:

我们定义了三个重载函数,虽然它们都有同一个名字,作用域也相同,但是参数列表不同,编译器根据实参的类型确定应该调用哪一个函数。

注:

main函数不能重载。

除了返回值不同,其他要素都相同的函数无法构成重载,属于重定义。



判断两个形参的类型是否相异

有时候两个形参列表看起来不一样,但实际上是相同的。下面两种函数声明。

Record lookup(const Account& acct);
Record lookup(const Account&) //省略了形参名
第一个函数形参有形参名,第二个函数灭有,并没有构成重载。因为形参名可有可无,只是起到帮助记忆的作用,并不影响形参列表的内容。
typedef Phone Telno;
Record lookup(const Account&);
Record lookup(const Telno&);
Telno和Phone是同一种类型,Telno只是Phone的别名而已。本质上两个函数没有区别,无法构成函数重载。


重载和const形参

我们知道:顶层const可以表示任意的对象常量,对于任何数据类型都适用,如算术运算类型,类、指针等。底层const则与指针和引用等符合类型部分有关,表示指针或引用所指的对象是一个常量。)

顶层const不影响传入的函数对象,一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开来。

Record lookup(Account);
Record lookup(const Account);//重复声明Record lookup(Account)

Record lookup(Account *);
Record lookup(Account * const);//重复声明Record lookup(Account)
在这两组声明中,每一组两个函数都是等价的

如果形参是某种类型的指针或引用,则通过区分其指向的是常量对象还是非常量对象可以实现函数重载,此时const是底层的

Record lookup(Account&);	//函数作用于Account的引用
Record lookup(const Account&);	//新函数,作用于常量引用

Record lookup(Account *);	//函数作用于指向Account的指针
Record lookup(const Account *);	//新函数,作用于指向常量的指针
对于接受引用或指针的函数来说,对象是常量还是非常量对应的形参是不同的。
在上面的例子中,编译器可以通过实参是否是常量来推断应该调用哪一个函数,因为const不能转化为其他类型,所以只能把const对象(或指向const的指针)传递给const的形参。相反的,因为非常量可以转化为const,所以上面的4个函数都能作用于非常量对象或者指向非常量对象的指针,不过,编译器会优先选用非常量版本的函数。


C++是如何实现函数重载的呢?

解答:因为C++编译器会对函数名进行改写,根据参数列表不同,改写其函数名,这样就区分出来了。

(C++难学原因之一就是因为编译器对代码插手太多,导致不能透过现象看本质)

例如:下列四个test()函数构成了重载,但是test函数只有声明,没有定义,在链接时,会报出无法解析的函数名的错误。

#include <iostream>

void test(int);
void test(char);
void test(double);
void test(float);

int main()
{
	int i = 0;
	char c = 0;
	double d = 0;
	float f = 0;

	test(i);
	test(c);
	test(d);
	test(f);

	return 0;
}
编译之后的错误提示:

1>正在链接...
1>test.obj : error LNK2019: 无法解析的外部符号 "void __cdecl test(float)" (?test@@YAXM@Z),该符号在函数 _main 中被引用
1>test.obj : error LNK2019: 无法解析的外部符号 "void __cdecl test(double)" (?test@@YAXN@Z),该符号在函数 _main 中被引用
1>test.obj : error LNK2019: 无法解析的外部符号 "void __cdecl test(char)" (?test@@YAXD@Z),该符号在函数 _main 中被引用
1>test.obj : error LNK2019: 无法解析的外部符号 "void __cdecl test(int)" (?test@@YAXH@Z),该符号在函数 _main 中被引用
1>E:\documents\vs2008\project\C++函数重载\Debug\C++函数重载.exe : fatal error LNK1120: 4 个无法解析的外部命令
可以发现,函数名都被改写了,这样在链接时就可以根据改写后的函数名来找到对应的函数体。

注:C语言也会对函数名进行改写,但是只是简单的在在函数名前添加下划线‘_’,不会考虑参数的部分,所以C语言没有函数重载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值