C++函数重载

2018-06-08  本文已影响7人  OriginalS_TZ

我们知道,函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数

那么为什么我们不能通过返回类型的不同来进行函数重载?

因为在编译中,每一个函数都会按照一定的规则进行映射

test.cpp

namespace t{
    float test(float i)
    {
        i = 1.2;
        return i;
    }

    float test() {
        return 1.2;
    }
}

float test(float i) {
    i = 3.4;
    return i;
}

int test(int i)
{
    i = 1;
    return i;
}

float output(float i, int d) {
    d = 3;
    i = 1.4;
    return i;
}

然后我们查看它的汇编代码

g++ -g -c test.cpp
objdump -S test.o > test_obj.s //可以和源代码一起看,酸爽!

1.o:    file format Mach-O 64-bit x86-64

Disassembly of section __TEXT,__text:
__ZN1t4testEf:
; {
       0:   55  pushq   %rbp
       1:   48 89 e5    movq    %rsp, %rbp
       4:   f3 0f 10 0d 8c 00 00 00     movss   140(%rip), %xmm1
       c:   f3 0f 11 45 fc  movss   %xmm0, -4(%rbp)
; i = 1.2;
      11:   f3 0f 11 4d fc  movss   %xmm1, -4(%rbp)
; return i;
      16:   f3 0f 10 45 fc  movss   -4(%rbp), %xmm0
      1b:   5d  popq    %rbp
      1c:   c3  retq
      1d:   0f 1f 00    nopl    (%rax)

__ZN1t4testEv:
; float test() {
      20:   55  pushq   %rbp
      21:   48 89 e5    movq    %rsp, %rbp
      24:   f3 0f 10 05 70 00 00 00     movss   112(%rip), %xmm0
; return 1.2;
      2c:   5d  popq    %rbp
      2d:   c3  retq
      2e:   66 90   nop

__Z4testf:
; float test(float i) {
      30:   55  pushq   %rbp
      31:   48 89 e5    movq    %rsp, %rbp
      34:   f3 0f 10 0d 64 00 00 00     movss   100(%rip), %xmm1
      3c:   f3 0f 11 45 fc  movss   %xmm0, -4(%rbp)
; i = 3.4;
      41:   f3 0f 11 4d fc  movss   %xmm1, -4(%rbp)
; return i;
      46:   f3 0f 10 45 fc  movss   -4(%rbp), %xmm0
      4b:   5d  popq    %rbp
      4c:   c3  retq
      4d:   0f 1f 00    nopl    (%rax)

__Z4testi:
; {
      50:   55  pushq   %rbp
      51:   48 89 e5    movq    %rsp, %rbp
      54:   89 7d fc    movl    %edi, -4(%rbp)
; i = 1;
      57:   c7 45 fc 01 00 00 00    movl    $1, -4(%rbp)
; return i;
      5e:   8b 45 fc    movl    -4(%rbp), %eax
      61:   5d  popq    %rbp
      62:   c3  retq
      63:   66 66 66 66 2e 0f 1f 84 00 00 00 00 00  nopw    %cs:(%rax,%rax)

__Z6outputfi:
; float output(float i, int d) {
      70:   55  pushq   %rbp
      71:   48 89 e5    movq    %rsp, %rbp
      74:   f3 0f 10 0d 28 00 00 00     movss   40(%rip), %xmm1
      7c:   f3 0f 11 45 fc  movss   %xmm0, -4(%rbp)
      81:   89 7d f8    movl    %edi, -8(%rbp)
; d = 3;
      84:   c7 45 f8 03 00 00 00    movl    $3, -8(%rbp)
; i = 1.4;
      8b:   f3 0f 11 4d fc  movss   %xmm1, -4(%rbp)
; return i;
      90:   f3 0f 10 45 fc  movss   -4(%rbp), %xmm0
      95:   5d  popq    %rbp
      96:   c3  retq

从上面我们不难看出

根据上面的对比,我们大致可以推断出命名规则为作用域+函数名+参数类型

例如 : ZN1t4 和Z4 代表两个不同的作用域

而output的Z6 output fi中的fi则表示的是参数类型,f表示float,i表示int

综上所述,映射后的函数名完全没有返回值什么事,当你调用一个函数,编译器首先要看看函数名列表,然后根据你的参数进行一个匹配

重载中最重要的就是对应函数的查找,为了正确查找函数,我们不能定义两个参数类型和函数名一样的函数,这是编译器生成的代码规则所决定的

如果你两个函数的作用域,函数名,参数类型都一样,那么也查找不到对应的函数了,如下(错误的代码)

//汇编之后的函数名(用下划线分割规则)
int test() {return 1;} 
//__Zn_test_v
float test() {return 1.2;}
//__Zn_test_v
//两个都是一样的,二义性

这就是为什么不能仅仅通过返回值类型不同来进行重载

上一篇 下一篇

猜你喜欢

热点阅读