.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset8
.cfi_offset5, -8
movl %esp, %ebp
.cfi_def_cfa_register5
andl $-16, %esp
subl $16, %esp
call_Z4funcv
movl $5, (%esp)
call_Z4funci
movl $0x40a00000, %eax
movl %eax,4(%esp)
movl $5, (%esp)
call_Z4funcif
movl $0, %eax
leave
.cfi_restore5
.cfi_def_cfa4,4
ret
.cfi_endproc
可以看到,func 的三个版本重载函数在编译后名字都被破坏了,编译器将他们重命名为了 _Z4funcv, _Z4funci, _Z4funcif, (g++ 编译器可能根据函数参数类型为函数名加上了与参数类型相关的特定后缀,如func(void) 变成了 _Z4funcv, func(int) 变成了_Z4funci , func(int, float)变成了 _Z4funcif ),然后在调用各个版本的func()时,编译器根据参数类型的不同选择合适的重载函数,如调用 func() 其实是调用了 _Z4funcv, 调用 func(5, 5.0)实际上是调用了 _Z4funcif等。
但是,在很多情况下,利用可变参数可以实现 C 语言的函数重载的,POSIX 接口中定义的 open 函数就是一个非常好的例子,
#include <sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
intopen(constchar*pathname,intflags);
intopen(constchar*pathname,intflags, mode_t mode);
第二个 open 函数的第三个参数用来表明创建文件的权限,所以这就是 C 实现函数重载活生生的例子 :-)
那么如何实现 C 的函数重载呢,比较通用的做法是利用 C 的可变参数va_args:
#include <stdarg.h>
voidva_start(va_list ap, last);
type va_arg(va_list ap, type);
voidva_end(va_list ap);
voidva_copy(va_list dest, va_list src);
以下是一个简单的例子,"重载"了两个函数,第一个函数是两个参数,第二个函数带了三个函数,其中第三个函数是可选的,
#include <stdio.h>
#include<stdarg.h>
voidva_overload2(intp1,intp2)
{
printf("va_overload2 %d %d\n", p1, p2);
}
voidva_overload3(intp1,intp2,intp3)
{
printf("va_overload3 %d %d %d\n", p1, p2, p3);
}
staticvoidva_overload(intp1,intp2, ...)
{
if(p2 ==3)
{
va_list v;
va_start(v, p2);
intp3 = va_arg(v,int);
va_end(v);
va_overload3(p1, p2, p3);
return;
}
va_overload2(p1, p2);
}
那么调用的时候可以如下调用:
#include <stdio.h>
intmain()
{
va_overload(1,2);
va_overload(1,2,3);
return0;
}
除了根据参数个数实现重载以外,还可以实现参数类型的重载(typeof),这主要是利用了 GCC 的内置函数,__builtin_types_compatible_p()和__builtin_choose_expr(),
例如:
structs1
{
inta;
intb;
doublec;
};
structs2
{
longlonga;
longlongb;
};
voidgcc_overload_s1(structs1 s)
{
printf("Got a struct s1: %d %d %f\n", s.a, s.b, s.c);
}
voidgcc_overload_s2(structs2 s)
{
printf("Got a struct s2: %lld %lld\n", s.a, s.b);
}
//warning: dereferencing type-punned pointer will break strict-aliasing rules
#definegcc_overload(A)\
__builtin_choose_expr(__builtin_types_compatible_p(typeof(A),structs1),\
gcc_overload_s1(*(structs1 *)&A),\
__builtin_choose_expr(__builtin_types_compatible_p(typeof(A),structs2),\
gcc_overload_s2(*(structs2 *)&A),(void)0))