C++是怎么区分同名的函数呢?原来是编译器悄悄使用了一个称作名字分裂规则的机制。
现代民俗给女孩子起名喜欢‘娜’、‘薇’等字,一个班出现两个‘李娜’,不是什么新鲜事,然而老师居然也能应付。老师是怎么做的呢?老师把她们的名字进行了扩展,把能区分她们一些特性加到姓名里来了,于是乎,出现了‘大李娜’、‘小李娜’、‘胖李娜’、‘瘦李娜’。假如她们高矮、胖瘦都一样,老师也有办法,把她们的家长找来开会:“有劳诸位阁下,请立即给你们的宝贝女儿改名”。
以Borland C++编译器为例,它等于说把我们写的每一个函数名都用一个新名字代替了。这个新名字由下列几部分组成:
‘@’+类名+‘@’+函数名+“$q”+参数类型符1+参数类型符2+…
其中,‘+’号是拼接在一起的意思。
参数类型符是这样的:
若无参数,则让它是字符‘v’(取void的字头);
若此参数是int型,则让它是字符i’;
若此参数是double型,则让它是字符d’,以此类推。
如下例所示:
class MyClass
{ public: :
valueX(int); //分裂为@MyClass@ valueX$qi
valueX(int, int ); //分裂为@MyClass@ valueX$qii
valueX(int,double); //分裂为@MyClass@ valueX$qid
valueX(double,int ); //分裂为@MyClass@ valueX$qdi
valueX(); //分裂为@MyClass@ valueX$qv
};
函数声明和定义时的名字变了,调用时函数的名字当然也必须变才能正确匹配。调用时的名字分裂如下所示:
int main()
{ MyClass obj;
:
obj. valueX(3); //分裂为@MyClass@ valueX$qi
obj.valueX(3, 3); //分裂为@MyClass@ valueX$qii
obj.valueX(3.0, 3); //分裂为@MyClass@ valueX$qdi
obj.valueX( ); //分裂为@MyClass@ valueX$qv
return0;
}
我们理所当然地感到,名字分裂这个词有点不恰当,似乎叫名字组合,或名字拼接才对。
至此,我们可以解开几个谜团:
①通过名字分裂以后,成员函数对编译系统来说就可以作为外部函数来处理,由此也可见C++是如何封装其成员函数的。如上例,如果我们在主函数里这样调用成员函数:valueX(3, 3),而不是obj.valueX(3,3),那么,它通过名字分裂之后是@ valueX$qii(3, 3),就不可能匹配到。
① C++为什么强调函数的原型形式?试想一下,如果不把参数类型逐一列出,编译系统怎么进行名字分裂?函数调用还能够匹配得上吗?
② C++规定,对于同名函数的参数,必须或者是个数不同,或者是参数类型的排列不同,或者二者皆不同。如果不如此规定,则分裂后的函数名相同。
我们看到,函数的返值类型并没有作为名字分裂的成分。也就是说,两个函数,如果除了返值类型不同之外,其余都相同,将会导致这两个函数进行名字分裂之后是一模一样的,这就出现了两意性(ambiguous),而计算机程序是绝不允许出现两意性的。
必须指出,名字分裂是在编译时进行的,而不是在运行时进行的。
博客地址:http://blog.csdn.net/chenshuzhenteacher/article/details/8066810