函数重载机制的奥秘

来源:互联网 发布:java阿里在线编程题 编辑:程序博客网 时间:2024/04/28 13:09


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

1 0
原创粉丝点击