个人总结:函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。
函数重载取决于参数的类型、个数,而跟返回类型无关。
这种形参类型、形参个数完全相同的函数也是可以重载的,只要它的const/volatiles属性不同即可。
在进行函数重载时,一般分为以下几步:
1>根据函数名确定候选函数集;
2>从候选函数集中选择可用函数集合;
3>从可用函数集中确定最佳函数,或由于模凌两可返回错误。
函数重载取决于参数的类型、个数,而跟返回类型无关。
在函数的重载中,我们只考虑:参数列表、函数名,不将函数返回类型考虑到函数重载中。
如:
#include<iostream>
using namespace std;
int max(int a,int b)
{
return a>=b?a:b;
}
double max(double a,double b)
{
return a>=b?a:b;
}
int main()
{
cout<<"max int is: "<<max(1,3)<<endl;
cout<<"max double is: "<<max(1.2,1.3)<<endl;
return 0;
}
什么是函数重载?
函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。
#include<iostream>
using namespace std;
void print(int i)
{
cout<<"print a integer :"<<i<<endl;
}
void print(string str)
{
cout<<"print a string :"<<str<<endl;
}
int main()
{
print(12);
print("hello world!");
return 0;
}
为什么需要函数重载(why)?
1、试想如果没有函数重载机制,如在C中,你必须要这样去做:为这个print函数取不同的名字,如print_int、print_string。这里还只是两个的情况,如果是很多个的话,就需要为实现同一个功能的函数取很多个名字,如加入打印long型、char*、各种类型的数组等等。这样做很不友好!
2、类的构造函数跟类名相同,也就是说:构造函数都同名。如果没有函数重载机制,要想实例化不同的对象,那是相当的麻烦!
3、操作符重载,本质上就是函数重载,它大大丰富了已有操作符的含义,方便使用,如+可用于连接字符串等!
函数重载的重要限定——作用域
以上的函数重载都是全局函数,下面我们来看一下一个类中的函数重载,用类的对象调用print函数,并根据实参调用不同的函数:
#include<iostream>
using namespace std;
class test{
public:
void print(int i)
{
cout<<"int"<<endl;
}
void print(char c)
{
cout<<"char"<<endl;
}
};
int main()
{
test t;
t.print(1);
t.print('a');
return 0;
}
编译器是如何解析重载函数调用的?
编译器实现调用重载函数解析机制的时候,肯定是首先找出同名的一些候选函数,然后从候选函数中找出最符合的,如果找不到就报错。
重载函数解析大致可以分为三步:
1>根据函数名确定候选函数集
2>从候选函数集中选择可用函数集合
3>从可用函数集中确定最佳函数,或由于模凌两可返回错误
根据函数名确定候选函数集
根据函数在同一作用域内所有同名的函数,并且要求是可见的(像private、protected、public、friend之类)。“同一作用域”也是在函数重载的定义中的一个限定,如果不在一个作用域,不能算是函数重载,如下面的代码:
void f(int);
void g()
{
void f(double);
f(1); //这里调用的是f(double),而不是f(int)
}
即内层作用域的函数会隐藏外层的同名函数!同样的派生类的成员函数会隐藏基类的同名函数。这很好理解,变量的访问也是如此,如一个函数体内要访问全局的同名变量要用“::”限定。
为了查找候选函数集,一般采用深度优选搜索算法:
step1:从函数调用点开始查找,逐层作用域向外查找可见的候选函数
step2:如果上一步收集的不在用户自定义命名空间中,则用到了using机制引入的命名空间中的候选函数,否则结束
在收集候选函数时,如果调用函数的实参类型为非结构体类型,候选函数仅包含调用点可见的函数;如果调用函数的实参类型包括类类型对象、类类型指针、类类型引用或指向类成员的指针,候选函数为下面集合的并:
(1)在调用点上可见的函数;
(2)在定义该类类型的名字空间或定义该类的基类的名字空间中声明的函数;
(3)该类或其基类的友元函数;
关于函数重载,一个被大多数遗忘或者疏漏的地方:
//这种形参类型、形参个数完全相同的函数也是可以重载的,只要它的const/volatiles属性不同即可!
//此例已经在VC++2010与GCC4.6.3测试通过
struct foo{
int bar() const {return 2;} ; //第一个重载函数
int bar() {return 1;}; //第二个重载函数
};
int main()
{
const foo a;
a.bar(); //单步跟踪,发现是调用第一个重载函数
foo b;
b.bar(); //单步跟踪,发现是调用第二个重载函数
}
一个简单的函数重载程序:
//函数的重载:只对于相同的函数,参数的个数、类型或顺序不同时,返回值不同
//输入2个参数时计算和
//输入3个参数时计算积
#include "stdafx.h"
#include<iostream>
using namespace std;
float sum(int a, int b);
float sum(int a, int b, int c);
int main(int argc, char* argv[])
{
float val = 0.0;
float val2 = 0.0;
int a = 5, b = 3, c = 7;
val = sum(a, b);
cout << "和:" << val << endl;
val2 = sum(a, b, c);
cout << "积:" << val2 << endl;
return 0;
}
float sum(int a, int b)
{
float SumVal = 0;
SumVal = a + b;
return SumVal;
}
float sum(int a, int b, int c)
{
float mul = 0;
mul = (float)a*b / c;
return mul;
}
部分内容参考:http://www.cnblogs.com/skynet/archive/2010/09/05/1818636.html