Const 重载解析(const参数重载 和 const成员函数重载)

来源:互联网 发布:数据有效性自定义公式 编辑:程序博客网 时间:2024/06/06 00:42

书上和网上在很多地方都对const 的重载做了一些解释,但感觉都不是很详细。还有很多同学在不同的地方发问关于const 重载的问题,这里我又重新看了一下,做了一个简单的分析也可能有不对的地方,欢迎讨论。
所谓重载,是指允许存在多个同名函数,而这些函数的参数表不同,即函数名相同但函数的签名不同。重载并不是面向对象编程的特有属性,这是因为重载是在编译阶段实现的,编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(这一点稍后有例子)。了

 

 Const 参数重载解析:

 

关于const 重载几乎在所有c++的书中者提到过但大部分只是一句话,例如在《C++ primer》一书中这样描述:“可基于函数的引用形参是指向 const 对象还是指向非 const 对象,实现函数重载。将引用形参定义为 const 来重载函数是合法的,因为编译器可以根据实参是否为 const 确定调用哪一个函数。”
但是这一段描述并没有给出引用、指针和值传递前加const的实质区别是什么。在用非const的指针,引用和值均可转化为const的。这一点没有太多可说明的东东。

对于函数值传递的情况,因为参数传递是通过复制实参创建一个临时变量传递进函数的,函数内只能改变临时变量,但无法改变实参。则这个时候无论加不加const对实参不会产生任何影响。但是在引用或指针传递函数调用中,因为传进去的是一个引用或指针,这样函数内部可以改变引用或指针所指向的变量,这时const 才是实实在在地保护了实参所指向的变量。因为在编译阶段编译器对调用函数的选择是根据实参进行的,所以,只有引用传递和指针传递可以用是否加const来重载。
下面给出一个例子可能就更明白了:

[cpp] view plaincopyprint?
  1. C++ 代码  
  2. #include<iostream>  
  3.   
  4.  class A{  
  5.  public:  
  6.     A();  
  7.     int foo(int *test);  
  8.     int foo(const int *test);  
  9. };  
  10. A::A(){  
  11. }  
  12.  int A::foo(int *test){  
  13.     std::cout << *test << " A::foo(int *test)" <<std::endl;  
  14.     return 1;  
  15. }  
  16.  int A::foo(const int *test){  
  17.     std::cout << *test << " A::foo(const int *test)" <<std::endl;  
  18.     return 1;  
  19. }  
  20.  int main()  
  21. {  
  22.     const int b =5;  
  23.     int c = 3;  
  24.     A a;  
  25.     a.foo(&b);  
  26.     a.foo(&c);  
  27.     return 1;  
  28. }  

输出:

[cpp] view plaincopyprint?
  1. A::foo(const int *test)  
  2. A::foo(int *test)  

那么编译器又是怎样工作的,通过g++ -S选项将汇编代码生成出来,通过AT&T汇编代码可以看出一些端倪来(之所以用AT&T汇编是因为VS生成的中间代码实在是让人头晕):

[cpp] view plaincopyprint?
  1. 代码  
  2. .file    "overload.cpp"  
  3.     .section    .ctors,"aw",@progbits  
  4.     .align 4  
  5.     .long    _GLOBAL__I__ZN1AC2Ev  
  6.     .text  
  7.     .align 2  
  8. .globl _ZN1AC2Ev  
  9.     .type    _ZN1AC2Ev, @function  
  10.  _ZN1AC2Ev:  
  11. .LFB1399:  
  12.     pushl    %ebp  
  13. .LCFI0:  
  14.     movl    %esp, %ebp  
  15. .LCFI1:  
  16.     popl    %ebp  
  17.     ret  
  18. .LFE1399:  
  19.     .size    _ZN1AC2Ev, .-_ZN1AC2Ev  
  20. .globl __gxx_personality_v0  
  21.     .align 2  
  22. .globl _ZN1AC1Ev  
  23.     .type    _ZN1AC1Ev, @function  
  24.  _ZN1AC1Ev:  
  25. .LFB1400:  
  26.     pushl    %ebp  
  27. .LCFI2:  
  28.     movl    %esp, %ebp  
  29. .LCFI3:  
  30.     popl    %ebp  
  31.     ret  
  32. .LFE1400:  
  33.     .size    _ZN1AC1Ev, .-_ZN1AC1Ev  
  34.     .align 2  
  35.     .type    _Z41__static_initialization_and_destruction_0ii, @function  
  36.  _Z41__static_initialization_and_destruction_0ii:  
  37. .LFB1411:  
  38.     pushl    %ebp  
  39. .LCFI4:  
  40.     movl    %esp, %ebp  
  41. .LCFI5:  
  42.     subl    $24, %esp  
  43. .LCFI6:  
  44.     movl    %eax, -4(%ebp)  
  45.     movl    %edx, -8(%ebp)  
  46.     cmpl    $1, -4(%ebp)  
  47.     jne    .L9  
  48.     cmpl    $65535, -8(%ebp)  
  49.     jne    .L9  
  50.     movl    $_ZSt8__ioinit, (%esp)  
  51.     call    _ZNSt8ios_base4InitC1Ev  
  52.     movl    $__dso_handle, 8(%esp)  
  53.     movl    $0, 4(%esp)  
  54.     movl    $__tcf_0, (%esp)  
  55.     call    __cxa_atexit  
  56. .L9:  
  57.     leave  
  58.     ret  
  59. .LFE1411:  
  60.     .size    _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii  
  61.     .align 2  
  62.     .type    _GLOBAL__I__ZN1AC2Ev, @function  
  63.  _GLOBAL__I__ZN1AC2Ev:  
  64. .LFB1413:  
  65.     pushl    %ebp  
  66. .LCFI7:  
  67.     movl    %esp, %ebp  
  68. .LCFI8:  
  69.     subl    $8, %esp  
  70. .LCFI9:  
  71.     movl    $65535, %edx  
  72.     movl    $1, %eax  
  73.     call    _Z41__static_initialization_and_destruction_0ii  
  74.     leave  
  75.     ret  
  76. .LFE1413:  
  77.     .size    _GLOBAL__I__ZN1AC2Ev, .-_GLOBAL__I__ZN1AC2Ev  
  78.     .align 2  
  79.     .type    __tcf_0, @function  
  80.  __tcf_0:  
  81. .LFB1412:  
  82.     pushl    %ebp  
  83. .LCFI10:  
  84.     movl    %esp, %ebp  
  85. .LCFI11:  
  86.     subl    $8, %esp  
  87. .LCFI12:  
  88.     movl    $_ZSt8__ioinit, (%esp)  
  89.     call    _ZNSt8ios_base4InitD1Ev  
  90.     leave  
  91.     ret  
  92. .LFE1412:  
  93.     .size    __tcf_0, .-__tcf_0  
  94.     .section    .rodata  
  95. .LC0:  
  96.     .string    " A::foo(const int *test)"  
  97.     .text  
  98.     .align 2  
  99. .globl _ZN1A3fooEPKi  
  100.     .type    _ZN1A3fooEPKi, @function  
  101.  _ZN1A3fooEPKi:  
  102. .LFB1402:  
  103.     pushl    %ebp  
  104. .LCFI13:  
  105.     movl    %esp, %ebp  
  106. .LCFI14:  
  107.     subl    $8, %esp  
  108. .LCFI15:  
  109.     movl    12(%ebp), %eax  
  110.     movl    (%eax), %eax  
  111.     movl    %eax, 4(%esp)  
  112.     movl    $_ZSt4cout, (%esp)  
  113.     call    _ZNSolsEi  
  114.     movl    $.LC0, 4(%esp)  
  115.     movl    %eax, (%esp)  
  116.     call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc  
  117.     movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)  
  118.     movl    %eax, (%esp)  
  119.     call    _ZNSolsEPFRSoS_E  
  120.     movl    $1, %eax  
  121.     leave  
  122.     ret  
  123. .LFE1402:  
  124.     .size    _ZN1A3fooEPKi, .-_ZN1A3fooEPKi  
  125.     .section    .rodata  
  126. .LC1:  
  127.     .string    " A::foo(int *test)"  
  128.     .text  
  129.     .align 2  
  130. .globl _ZN1A3fooEPi  
  131.     .type    _ZN1A3fooEPi, @function  
  132.  _ZN1A3fooEPi:  
  133. .LFB1401:  
  134.     pushl    %ebp  
  135. .LCFI16:  
  136.     movl    %esp, %ebp  
  137. .LCFI17:  
  138.     subl    $8, %esp  
  139. .LCFI18:  
  140.     movl    12(%ebp), %eax  
  141.     movl    (%eax), %eax  
  142.     movl    %eax, 4(%esp)  
  143.     movl    $_ZSt4cout, (%esp)  
  144.     call    _ZNSolsEi  
  145.     movl    $.LC1, 4(%esp)  
  146.     movl    %eax, (%esp)  
  147.     call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc  
  148.     movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)  
  149.     movl    %eax, (%esp)  
  150.     call    _ZNSolsEPFRSoS_E  
  151.     movl    $1, %eax  
  152.     leave  
  153.     ret  
  154. .LFE1401:  
  155.     .size    _ZN1A3fooEPi, .-_ZN1A3fooEPi  
  156.     .align 2  
  157. .globl main  
  158.     .type    main, @function  
  159.  main:  
  160. .LFB1403:  
  161.     leal    4(%esp), %ecx  
  162. .LCFI19:  
  163.     andl    $-16, %esp  
  164.     pushl    -4(%ecx)  
  165. .LCFI20:  
  166.     pushl    %ebp  
  167. .LCFI21:  
  168.     movl    %esp, %ebp  
  169. .LCFI22:  
  170.     pushl    %ecx  
  171. .LCFI23:  
  172.     subl    $36, %esp  
  173. .LCFI24:  
  174.     movl    $5, -8(%ebp)  
  175.     movl    $3, -12(%ebp)  
  176.     leal    -13(%ebp), %eax  
  177.     movl    %eax, (%esp)  
  178.     call    _ZN1AC1Ev  
  179.     leal    -8(%ebp), %eax  
  180.     movl    %eax, 4(%esp)  
  181.     leal    -13(%ebp), %eax  
  182.     movl    %eax, (%esp)  
  183.     call    _ZN1A3fooEPKi  
  184.     leal    -12(%ebp), %eax  
  185.     movl    %eax, 4(%esp)  
  186.     leal    -13(%ebp), %eax  
  187.     movl    %eax, (%esp)  
  188.     call    _ZN1A3fooEPi  
  189.     movl    $1, %eax  
  190.     addl    $36, %esp  
  191.     popl    %ecx  
  192.     popl    %ebp  
  193.     leal    -4(%ecx), %esp  
  194.     ret  
  195. .LFE1403:  
  196.     .size    main, .-main  
  197.     .local    _ZSt8__ioinit  
  198.     .comm    _ZSt8__ioinit,1,1  
  199.     .weakref    _Z20__gthrw_pthread_oncePiPFvvE,pthread_once  
  200.     .weakref    _Z27__gthrw_pthread_getspecificj,pthread_getspecific  
  201.     .weakref    _Z27__gthrw_pthread_setspecificjPKv,pthread_setspecific  
  202.     .weakref    _Z22__gthrw_pthread_createPmPK14pthread_attr_tPFPvS3_ES3_,pthread_create  
  203.     .weakref    _Z22__gthrw_pthread_cancelm,pthread_cancel  
  204.     .weakref    _Z26__gthrw_pthread_mutex_lockP15pthread_mutex_t,pthread_mutex_lock  
  205.     .weakref    _Z29__gthrw_pthread_mutex_trylockP15pthread_mutex_t,pthread_mutex_trylock  
  206.     .weakref    _Z28__gthrw_pthread_mutex_unlockP15pthread_mutex_t,pthread_mutex_unlock  
  207.     .weakref    _Z26__gthrw_pthread_mutex_initP15pthread_mutex_tPK19pthread_mutexattr_t,pthread_mutex_init  
  208.     .weakref    _Z26__gthrw_pthread_key_createPjPFvPvE,pthread_key_create  
  209.     .weakref    _Z26__gthrw_pthread_key_deletej,pthread_key_delete  
  210.     .weakref    _Z30__gthrw_pthread_mutexattr_initP19pthread_mutexattr_t,pthread_mutexattr_init  
  211.     .weakref    _Z33__gthrw_pthread_mutexattr_settypeP19pthread_mutexattr_ti,pthread_mutexattr_settype  
  212.     .weakref    _Z33__gthrw_pthread_mutexattr_destroyP19pthread_mutexattr_t,pthread_mutexattr_destroy  
  213.     .section    .eh_frame,"a",@progbits  
  214. .Lframe1:  
  215.     .long    .LECIE1-.LSCIE1  
  216. .LSCIE1:  
  217.     .long    0x0  
  218.     .byte    0x1  
  219.     .string    "zP"  
  220.     .uleb128 0x1  
  221.     .sleb128 -4  
  222.     .byte    0x8  
  223.     .uleb128 0x5  
  224.     .byte    0x0  
  225.     .long    __gxx_personality_v0  
  226.     .byte    0xc  
  227.     .uleb128 0x4  
  228.     .uleb128 0x4  
  229.     .byte    0x88  
  230.     .uleb128 0x1  
  231.     .align 4  
  232. .LECIE1:  
  233. .LSFDE5:  
  234.     .long    .LEFDE5-.LASFDE5  
  235. .LASFDE5:  
  236.     .long    .LASFDE5-.Lframe1  
  237.     .long    .LFB1411  
  238.     .long    .LFE1411-.LFB1411  
  239.     .uleb128 0x0  
  240.     .byte    0x4  
  241.     .long    .LCFI4-.LFB1411  
  242.     .byte    0xe  
  243.     .uleb128 0x8  
  244.     .byte    0x85  
  245.     .uleb128 0x2  
  246.     .byte    0x4  
  247.     .long    .LCFI5-.LCFI4  
  248.     .byte    0xd  
  249.     .uleb128 0x5  
  250.     .align 4  
  251. .LEFDE5:  
  252. .LSFDE7:  
  253.     .long    .LEFDE7-.LASFDE7  
  254. .LASFDE7:  
  255.     .long    .LASFDE7-.Lframe1  
  256.     .long    .LFB1413  
  257.     .long    .LFE1413-.LFB1413  
  258.     .uleb128 0x0  
  259.     .byte    0x4  
  260.     .long    .LCFI7-.LFB1413  
  261.     .byte    0xe  
  262.     .uleb128 0x8  
  263.     .byte    0x85  
  264.     .uleb128 0x2  
  265.     .byte    0x4  
  266.     .long    .LCFI8-.LCFI7  
  267.     .byte    0xd  
  268.     .uleb128 0x5  
  269.     .align 4  
  270. .LEFDE7:  
  271. .LSFDE9:  
  272.     .long    .LEFDE9-.LASFDE9  
  273. .LASFDE9:  
  274.     .long    .LASFDE9-.Lframe1  
  275.     .long    .LFB1412  
  276.     .long    .LFE1412-.LFB1412  
  277.     .uleb128 0x0  
  278.     .byte    0x4  
  279.     .long    .LCFI10-.LFB1412  
  280.     .byte    0xe  
  281.     .uleb128 0x8  
  282.     .byte    0x85  
  283.     .uleb128 0x2  
  284.     .byte    0x4  
  285.     .long    .LCFI11-.LCFI10  
  286.     .byte    0xd  
  287.     .uleb128 0x5  
  288.     .align 4  
  289. .LEFDE9:  
  290. .LSFDE11:  
  291.     .long    .LEFDE11-.LASFDE11  
  292. .LASFDE11:  
  293.     .long    .LASFDE11-.Lframe1  
  294.     .long    .LFB1402  
  295.     .long    .LFE1402-.LFB1402  
  296.     .uleb128 0x0  
  297.     .byte    0x4  
  298.     .long    .LCFI13-.LFB1402  
  299.     .byte    0xe  
  300.     .uleb128 0x8  
  301.     .byte    0x85  
  302.     .uleb128 0x2  
  303.     .byte    0x4  
  304.     .long    .LCFI14-.LCFI13  
  305.     .byte    0xd  
  306.     .uleb128 0x5  
  307.     .align 4  
  308. .LEFDE11:  
  309. .LSFDE13:  
  310.     .long    .LEFDE13-.LASFDE13  
  311. .LASFDE13:  
  312.     .long    .LASFDE13-.Lframe1  
  313.     .long    .LFB1401  
  314.     .long    .LFE1401-.LFB1401  
  315.     .uleb128 0x0  
  316.     .byte    0x4  
  317.     .long    .LCFI16-.LFB1401  
  318.     .byte    0xe  
  319.     .uleb128 0x8  
  320.     .byte    0x85  
  321.     .uleb128 0x2  
  322.     .byte    0x4  
  323.     .long    .LCFI17-.LCFI16  
  324.     .byte    0xd  
  325.     .uleb128 0x5  
  326.     .align 4  
  327. .LEFDE13:  
  328. .LSFDE15:  
  329.     .long    .LEFDE15-.LASFDE15  
  330. .LASFDE15:  
  331.     .long    .LASFDE15-.Lframe1  
  332.     .long    .LFB1403  
  333.     .long    .LFE1403-.LFB1403  
  334.     .uleb128 0x0  
  335.     .byte    0x4  
  336.     .long    .LCFI19-.LFB1403  
  337.     .byte    0xc  
  338.     .uleb128 0x1  
  339.     .uleb128 0x0  
  340.     .byte    0x9  
  341.     .uleb128 0x4  
  342.     .uleb128 0x1  
  343.     .byte    0x4  
  344.     .long    .LCFI20-.LCFI19  
  345.     .byte    0xc  
  346.     .uleb128 0x4  
  347.     .uleb128 0x4  
  348.     .byte    0x4  
  349.     .long    .LCFI21-.LCFI20  
  350.     .byte    0xe  
  351.     .uleb128 0x8  
  352.     .byte    0x85  
  353.     .uleb128 0x2  
  354.     .byte    0x4  
  355.     .long    .LCFI22-.LCFI21  
  356.     .byte    0xd  
  357.     .uleb128 0x5  
  358.     .byte    0x4  
  359.     .long    .LCFI23-.LCFI22  
  360.     .byte    0x84  
  361.     .uleb128 0x3  
  362.     .align 4  
  363. .LEFDE15:  
  364.     .ident    "GCC: (GNU) 4.1.2 20070925 (Red Hat 4.1.2-33)"  
  365.     .section    .note.GNU-stack,"",@progbits  

如上面的代码函数:

 

int foo(int *test);和int foo(const int *test);分别被编译器生成名为:_ZN1A3fooEPKi和_ZN1A3fooEPi(这两个名字会因为编译器的不同而不同,名字只是一个区分的符号而已不用深究,只用知道重载的函数经过编译器的处理函数名字已经发生了变化。所以对于后面的汇编和链接工作就不存在重载的问题了。)这里也同时说明对重载来说在编译阶段已经完成。

对于a.foo(&b);因为变量b有const修饰所以就调用了int foo(const int *test);对于a.foo(&c);调用int foo(int *test);因为这个是精确匹配的。但是如果没有定义int foo(const int *test);则在代码24行会出现编译错误。反过来如果没有定义函数:int foo(int *test);如下:

[cpp] view plaincopyprint?
  1. 代码  
  2. #include<iostream>  
  3.   
  4.  class A{  
  5.  public:  
  6.     A();  
  7.  //    int foo(int *test);  
  8.      int foo(const int *test);  
  9. };  
  10. A::A(){  
  11. }  
  12.  /*int A::foo(int *test){ 
  13.     std::cout << *test << " A::foo(int *test)" <<std::endl; 
  14.     return 1; 
  15. } 
  16. */  
  17. int A::foo(const int *test){  
  18.     std::cout << *test << " A::foo(const int *test)" <<std::endl;  
  19.     return 1;  
  20. }  
  21. int main()  
  22. {  
  23.     const int b =5;  
  24.     int c = 3;  
  25.     A a;  
  26.     a.foo(&b);  
  27.     a.foo(&c);  
  28.     return 1;  
  29. }  

则输出结果为:

[cpp] view plaincopyprint?
  1. 5 A::foo(const int *test)  
  2. 3 A::foo(const int *test)  

原因c++ primer上讲的很清楚:“We can use a nonconst object to initializer either a const or nonconst reference. However, initializing a constreference to a nonconst object requires a conversion, whereas initializing a nonconst parameter is an exact match.”

 

 

const 成员函数重载的解析:

 

const 成员函数重载的解析和const参数重载解析的原理可以说是一样的。之所以这样说是因为const成员函数的解析可被看做是对函数this参数用const来修饰的过程。例如下面代码:

[cpp] view plaincopyprint?
  1. 代码  
  2. #include<iostream>  
  3.   
  4. class A{  
  5. public:  
  6.     A();  
  7.     int foo(int *test); //可看做:int foo(A *this,int *test);  
  8.     int foo(int *test) const;//可看做:int foo(const A *this,int *test);  
  9. };  
  10. A::A(){  
  11. }  
  12. int A::foo(int *test){  
  13.     std::cout << *test << "foo" <<std::endl;  
  14.     return 1;  
  15. }  
  16. int A::foo(int *test) const {  
  17.     std::cout << *test << "foo const" <<std::endl;  
  18.     return 1;  
  19. }  
  20. int main()  
  21. {  
  22.     int b = 5;  
  23.     const A a;  
  24.     a.foo(&b);  
  25.     return 1;  
  26. }  

上面可以看到编译阶段的调用也是通过对重载函数的别名来实现的。

总结:

1.const重载主要是通过能否对传入的参数进行修改为判断的。http://blog.csdn.net/net_assassin/article/details/9997257

2.const参数重载和const函数重载机制都是一样的,因为对于const 函数重载可看做是对隐含的指针this的参数重载。

3.重载是在编译阶段已经完成,对于汇编和链接来说透明的。





FROM:http://blog.csdn.net/net_assassin/article/details/9997257

0 0