老师是这么给我们开篇的:
有这么一个函数:
max(),它的作用是比较两个数的大小。然后呢,我们就会想,是比较两个int数据的大小呢,还是比较char数据的大小呢,还是比较double数据的大小呢。
当然,编写一个max()总不可能完成比较任意数大小的功能。这个函数可以这么定义:
int max(int a, int b)
{
return a > b ? a : b;
}
那么,在C中,我们必须要编写很多个不同类型参数和返回值的函数才能够满足我们比较多种数据大小的问题。也就意味着,完成这样一个功能,我们得有多个不同函数,函数名不同,参数和返回类型不同,可是多种函数名却带来很多不便。否则,最有可能出现的编译错误便是:重定义!也就是说一个变量或者标示符被定义了多次。但是这样的一批函数,它们的函数体却是相同的。很麻烦。
但是在C++中,函数的重载,为我们提供了这样一种便利。就是说:我们可以使用相同的函数名,仅仅改变它的返回值类型和参数类型,就可以实现不同类型的数据比较。
(当然了,在C++中模板可能更为方便,暂不讨论)
例如:
int max(int a, int b)
{
return a > b ? a : b;
}
double max(double a, double b)
{
return a > b ? a : b;
}
char max(char a, char b)
{
return a > b ? a : b;
}
上面的这种定义方式,在C语言中,是绝对不允许的,因为编译错误:重定义。
但是在C++中,却提供了我们这种便利。完全正确,没有错误。我们可以认为,这就是函数重载。
当你需要比较不同某种数据类型的两个数的时候,你可以选择特定的函数。
甚至:
int max(int a, double b)
{
return a > b ? a : b;
}
也可以。
那么,为什么C++中,可以实现函数的重载呢。可以肤浅的这么来讲:C++编译器识别两个函数名称相同的函数不是单单由函数名称确定它们两是不是一样。而是根据函数调用约定确定由函数名修饰规则修饰后的函数名原型是不是一样的。而函数名原型包括了:自己定义的函数名 + 此函数使用的函数调用约定 + 函数返回值类型 + 函数参数类型及个数。
举个例子:C++编译器默认的函数调用约定是_cdecl那么对于int _cdecl max(int a, int b);来说,在C++编译器编译后(经过了函数名修饰),此函数的函数原型为:
?max@@YAHHH@Z
其中?总是必须的,max作为函数定义者定义的名称,对不同函数来说必然是不同的,@@YA代表了特定的函数调用约定(有关函数调用约定的问题,下篇文章再谈)
第一个H,代表了返回值类型为int类型,第二个H代表了函数的第一个参数为int类型,第二个H代表了函数第二个参数为int类型。对于有参函数来说末尾均以@Z结束。
看到了没,
这样一来,对于不同返回值类型,不同参数类型,不同函数调用约定的函数,其经过函数名修饰后的函数名原型必然是不同的。
由此,我们的C++编译器,便区别了以上均为max()的函数没有重定义,而是函数的重载。
那么为什么C不可以呢,简单的说就是:C编译器,从根本上,不支持函数重载。具体为什么不支持的原因,我也不懂。但是,可以借助函数调用约定证明,C语言不支持重载绝对是由于C编译器根本上不支持造成的。
这个实验加证明的方法,很简单,下篇学习笔记中说函数调用约定和函数名修饰规则的时候,再谈啦。