`
java-mans
  • 浏览: 11414362 次
文章分类
社区版块
存档分类
最新评论

重载函数

 
阅读更多

函数的重载
对于出现在相同作用域的两个函数,如果它们的名字相同,而行参不同,则称为重载函数。
举一个简单的例子,假设电话号码本中有序号、人名,号码等信息。我们希望通过一个输入其中的一个来或得这个人完整的信息。
要完成这个功能,我们需要定义3个函数:

	Record lookup(const Account&);  // find by Account 
	Record lookup(const Phone&);    // find by Phone 
	Record lookup(const Name&);     // find by Name 
	Record r1, r2; 
	r1 = lookup(acct);                  // call version that takes an Account 


搜索函数的名字通常都定义的相同(没有人希望对于不同的搜索内容,还要掌握不同的函数名),但是这些函数的形参却不相同(可以是序号,也可以是人名,也可以是电话号码)。
注意:如果两个函数声明的返回类型和形参列表完全匹配,则第二个函数是第一个函数的重复声明;如果两个函数仅是返回类型不同,而行参列表相同,则第二个函数是错误的。


重载函数的关键是编译器如何决定在调用该函数时,使用重载函数中的哪一个。

先看一个特殊的情况,两个函数在不同的作用域中:
在定义变量时,我们知道,局部变量会屏蔽全局变量;同理局部函数(虽然我们很少这样定义),则会屏蔽全局的重载函数,举一个例子:

	void print(const string &); 
	void print(double);   // overloads the print function 
	void fooBar(int ival) 
	{ 
		void print(int);   // new scope: hides previous instances of print 
		 print("Value: ");  // error: print(const string &) is hidden 
		print(ival); // ok: print(int) is visible 
		print(3.14); // ok: calls print(int); print(double) is hidden 
	}


这是因为,调用 print 时,编译器首先检索这个名字的声明,找到只有一个 int 型形参的 print 函数的局部声明。一旦找到这个名字,编译器将不再继续检查这个名字是否在外层作用域中存在,即编译器将认同找到的这个声明即是程序需要调用的函数,余下的工作只是检查该名字的使用是否有效。

所以,下面的情况才会调用重载函数:

	void print(const string &); 
	void print(double); // overloads print function 
	void print(int);    // another overloaded instance 
	void fooBar2(int ival) 
	{ 
		print("Value: "); // ok: calls print(const string &) 
		print(ival);      // ok: print(int) 
		print(3.14);      // ok: calls print (double) 
	


如何确定到底使用的是哪个函数呢?举一个例子来说明:

	void f(); 
	void f(int); 
	void f(int, int); 
	void f(double, double = 3.14); 
	f(5.6); 


首先要先确定候选函数,就是那些作用域相同,且名字相同的函数,这里的4个都是。
其次要选出可行的函数:形参个数与实参个数相同,形参类型与实参类型相匹配,或者实参能够隐式的转换为形参。特别要注意,因为有的函数可能提供了默认参数,所以在调用时,实参可能会比需求的少。
在这里,对于f(5.6),肯定不对的是void f()和void f(int, int),因为它们参数的个数不匹配。而void f(int)是可行的,因为可以通过隐式转换将double转为int;void f(double, double = 3.14);也是可行的,因为它的第二个参数提供了默认实参,而第一个形参则与实参完全匹配。
最后需要寻找最佳匹配。最佳指得是实参类型与形参类型越接近越好。所以,编译器会选用void f(double, double = 3.14),因为这里实参与形参的类型完全相同,而void f(int)还需要转化。
当然,也会出现找不到最佳匹配的情况,比如调用f(42, 2.56)时,void f(int, int)与void f(double, double = 3.14)都有一个实参精确匹配,另一个实参需要转化。出现这种情况,往往意味着你的重载函数设计的不合理。

有一点也需要注意如果函数返回值类型,函数名,形参都相同,唯一的区别在于形参多了const限定符修订的话,这种情况不属于重载,只是重复声明。原因在于函数在传递实参时,不论型参是否为const,都会复制实参,而且对形参的修改不会影响实参。所以,可以将const实参传递给const形参,也可以传递给非const形参。二者并无本质区别。

最后考虑类中的情况。在类中,也会遇到函数重载,规则跟上面是一样的,唯一要注意的是,成员函数只能重载本类的其他成员函数,不能重载其他类的成员函数或者类外的成员函数。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics