默认参数半缺省参数必须从右往左依次来给出,不能间隔着给 缺省参数不能在函数声明和定义中同时出现 缺省值必须是常量或者全局变量 函数重载C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表参数个数 或 类型 或 顺序 必须不同,可以通过函数重载实现编译时多态
注意事项由于函数传参为值拷贝,所以在没有最合适的匹配函数时,会生成临时变量来匹配对应实参 1 2 3 4 5 6 void Fuc (int a) {}int main () { Fuc(3.14 ); return 0 ; }
当没有最合适匹配,但能匹配的函数不唯一时,编译器会报错 1 2 3 4 5 6 7 void Fuc (long a) {}void Fuc (int a) {}int main () { Fuc(3.14 ); return 0 ; }
匹配成功的前提是:该函数每个实参的匹配都不劣于其他可行函数需要的匹配,至少一个实参的匹配优于其他可行函数提供的匹配 匹配等级:
精准匹配:实参类型和形参相同、实参从数组类型或函数类型转换成对应的指针类型、向实参添加顶层const或者从实参中删除顶层const 通过const转换实现的匹配 通过类型提升实现的匹配 通过算术类型转换或指针转换实现的匹配 通过类类型转换实现的匹配 如: 1 2 3 4 5 6 7 void Fuc (const double a) {};void Fuc (double a) {};int main () { Fuc(3.14 ); return 0 ; }
1 2 3 4 5 6 7 void Fuc (const int a) {}void Fuc (double a) {}int main () { Fuc(3.14 ); return 0 ; }
重载引用/指针参数1 2 3 4 5 6 7 8 9 10 void Fuc (int * a) {}void Fuc (const int * a) {}int main () { const int a = 3 ; int b = 1 ; Fuc(&a); Fuc(&b); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 void Fuc (double & a) {}void Fuc (const double & a) {}void Fuc (double && a) {}int main () { double a = 3.14 ; int b = 3 ; Fuc(a); Fuc(b); Fuc(3.14 + 1 ); Fuc(3.14 ); return 0 ; }
原理拿这段代码来说
1 2 3 4 5 6 7 void Print (int a, double b, char c) {}void Print (int * a, double * b, char * c) {}int main () { Print(3 , 3.14 , 'a' ); return 0 ; }
在linux下执行命令objdump -d a.out |less反汇编。仅展示部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 000000000040062d <_Z5Printidc>: 40062d: 55 push %rbp 40062e: 48 89 e5 mov %rsp,%rbp 400631: 89 7d fc mov %edi,-0x4(%rbp) 400634: f2 0f 11 45 f0 movsd %xmm0,-0x10(%rbp) 400639: 89 f0 mov %esi,%eax 40063b: 88 45 f8 mov %al,-0x8(%rbp) 40063e: 5d pop %rbp 40063f: c3 retq 0000000000400640 <_Z5PrintPiPdPc>: 400640: 55 push %rbp 400641: 48 89 e5 mov %rsp,%rbp 400644: 48 89 7d f8 mov %rdi,-0x8(%rbp) 400648: 48 89 75 f0 mov %rsi,-0x10(%rbp) 40064c: 48 89 55 e8 mov %rdx,-0x18(%rbp) 400650: 5d pop %rbp 400651: c3 retq 0000000000400652 <main>: 400652: 55 push %rbp 400653: 48 89 e5 mov %rsp,%rbp 400656: 48 83 ec 08 sub $0x8,%rsp 40065a: 48 b8 1f 85 eb 51 b8 movabs $0x40091eb851eb851f,%rax 400661: 1e 09 40 400664: be 61 00 00 00 mov $0x61,%esi 400669: 48 89 45 f8 mov %rax,-0x8(%rbp) 40066d: f2 0f 10 45 f8 movsd -0x8(%rbp),%xmm0 400672: bf 03 00 00 00 mov $0x3,%edi 400677: e8 b1 ff ff ff callq 40062d <_Z5Printidc> 40067c: b8 00 00 00 00 mov $0x0,%eax 400681: c9 leaveq 400682: c3 retq
Print(int a, double b, char c)的函数签名变为<_Z5Printidc> Print(int* a, double* b, char* c)的函数签名变为<_Z5PrintPiPdPc>
验证其他代码后,可以发现大概是int->i,long->l,char->c,string->Ss…基本上都是用首字母代表
编译器实际在底层使用被重新修饰过的一个比较复杂的名字,被重新修饰后的名字中包含了:函数的名字以及参数类型。这就是为什么函数重载中几个同名函数要求其参数列表不同的原因。linux 下函数名修饰规则:_Z + 名称空间 + 函数字符个数 + 函数名 + 类型首字符
有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译
1 2 3 4 5 6 extern "C" void Print (int a, double b, char c) {}int main () { Print(3 , 3.14 , 'a' ); return 0 ; }
在linux下执行命令objdump -d a.out |less反汇编。仅展示部分:
1 2 3 4 5 6 7 8 9 000000000040062d <Print>: 40062d: 55 push %rbp 40062e: 48 89 e5 mov %rsp,%rbp 400631: 89 7d fc mov %edi,-0x4(%rbp) 400634: f2 0f 11 45 f0 movsd %xmm0,-0x10(%rbp) 400639: 89 f0 mov %esi,%eax 40063b: 88 45 f8 mov %al,-0x8(%rbp) 40063e: 5d pop %rbp 40063f: c3 retq
由于C语言只是单纯的函数名。因此当工程中存在相同函数名的函数时,就会产生冲突