函数的重载

在面向过程的编程模式下,程序被划分为数据结构+函数,这也就是那句著名的"程序=数据结构+算法"的由来
在面向过程的思考方式下,函数名就是最好的标识,而名称组织良好的函数集合是判断代码是否优美的一个重要因素

在面向对象的思考方式下,一切都不同了

常见的情况下,应该为不同的函数起不同的名字,但是当这些函数要完成相同的功能而仅仅是要处理的参数类型不同时,
根据完成的功能而给这些函数一个相同的名字反到更符合我们的生活习惯,例如我们熟悉的print函数
void print(int); //打印一个整数
void print(float); //打印一个浮点数
void print(const char*); //打印一个字符串
...

如果我们不得不把这些函数声明为
void print_int(int); //打印一个整数
void print_float(float); //打印一个浮点数
void print_str(const char*); //打印一个字符串
...
就有些笨拙了,如果不考虑系统对隐式类型转换的支持,我们甚至需要为8种整型数据分别命名不同的函数
这可以让程序员写出更健壮的代码,有人或许要开始争辩了
不是吗,你只能写printInt(3)而不可能写出printInt(3.2)的代码,如果名称只有一个,那么
print(3),这到底该调用哪一个函数呢?

对,我承认这种笨拙的命名方式会带来一些健壮性的好处,但是这是以降低程序员工作效率为代价的,说到底,这仍然是一个取舍,
仅仅就这个问题,其实我们谁也所服不了谁的,那么请看看下一个例子

int i = 10;
float f = 10f;
double d = 10;
i + f;
i + d;
f + d;

对于运算符+来说,这里其实就是一个同样函数名的例子.对于C++来说,它支持运算符的重定义,这也是让用户自定义类型具有内置类型同样的能力的原则体现,
那么这里就不得不支持同名的函数,另外也需要说明一下,在一个函数只有一个名称的情况下,如果多个参数具有不同的类型,这种规则很快会导致函数名称的
膨胀,在C语言中,几万行代码的一个文件的情况是很常见的,也有这方面的原因

好了,好了,现在的问题已经不是是否需要函数同名的问题了,现在的问题是我们如何解决函数同名的问题
毕竟对于编译器来说,函数名称就是它的符号表内容,如果一组函数具有相同的名称,那么编译器就必须自己把它们区别开来

这个问题的解决其实非常简单,就是名称重整(name-mangling),编译器根据函数的名称和所有参数的类型为这个函数重新整理一个函数名称,并用这个整理后的名称作为标识,当然
,显示的时候我们可不想看到那一长串名称,因此这个名称重整还必须能够很容易的得到原始的函数名,例如以下函数的名称重整
转换前
void print(int); //打印一个整数
void print(float); //打印一个浮点数
void print(const char*); //打印一个字符串
...
转换后:
void print_int(int); //打印一个整数
void print_float(float); //打印一个浮点数
void print_str(const char*); //打印一个字符串
...
呵呵,还不是C语言的老把戏,只不过这次是编译器来做,而不是程序员做的而已
嗯,如果泛泛的说,C++不过是把以前许多C语言的实现方式固定化,并移到了编译器层次来实现而已

另一个更重要的问题是,程序员也不会写那个编译器自己才认识的重整名字,因此当程序员写出
print(3)这样的代码以后,编译器还必须把这里的print调用编译成它可以认识的重整名称,而这就有些难度了

基本的想法是编译器必须去挑选那个参数匹配最好的函数,而到底什么才算是匹配最好呢?C++给出了一套复杂的匹配规则:
1.准确匹配:也就是说,无须任何转换或者只需要一些微不足道的转换(例如数组名到指针,函数名到函数指针,T到const T等)
2.提升匹配:也就是说,只需要类型升级后就可以匹配的(例如bool到int,short到int,float到double等)
3.标准匹配:也就是说,利用标准支持的一些类型转换(例如int到double,double到int,Derived*到Base*,T*到void*等)
4.用户匹配:也就是说,利用用户自定义的类型转换
5.省略匹配:也就是说,利用...参数进行匹配
这5个规则是5个层次,依照从上向下的顺序执行,如果分析到某个层次却发现了两个以上的匹配则被认为歧义

重载规则与函数的声明次序和函数的返回值无关,更特别的重载规则与不同的非名字空间作用域也无关
这样的规定将避免重载规则与具体的调用环境相关,我们不想让已经够复杂的规则更加复杂

重载不能跨作用域,这将导致艰难的权衡
如果是有意识的用同名的函数去屏蔽,这就是一个很有用的技术,使我们的小世界可以免收外界的干扰
如果是无意识的用同名的函数去屏蔽,这就是一个很糟糕的技术,使我们的小世界和外面的世界失去了联系

权衡是如此的困难,因此还必须保留一扇门,如果希望重载能够跨越类或者名字空间的作用域,可以使用using使用声明 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值