小记:静默如初,安之若素
1.函数重载
- 定义
在相同的作用域,定义同名的函数,但是它们的参数要有所区分,这样的多个函数构成重载关系。
注:函数的重载和返回值无关
eg: 图像库(包含很多绘图函数)
//C语言实现(C语言不能有同名函数)
void drawCircle(int x, int y, double r){...}
void drawRect(int x, int y, double w, double h){...}
...
//C++语言实现
void draw(int x, int y, double r){...}
void draw(int x, int y, double w, double h){...}
...
1 #include <iostream>
2 using namespace std;
3
4 int foo(int a)
5 {
6 cout<<"foo(int)"<<endl;
7 }
8
9 void foo(int a, int b)
10 {
11 cout<<"foo(int, int)"<<endl;
12 }
13
14 void foo(int a, float b)
15 {
16 cout<<"foo(int, float)"<<endl;
17 }
18
19 int main(int argc, char * argv[])
20 {
21 foo(10);//foo(int)
22 foo(10, 20);//foo(int, int)
23 //foo(10, 3.14); //直接传实参3.14出错,实参默认为double
24 //error: call of overloaded ‘foo(int, double)’ is ambiguous
25 foo(10, 3.14f);//标明格式就可以. foo(int, float)
26
27 //通过函数指针调用重载关系的函数,
28 //实际调用哪个版本是由指针类型决定,而不是由实参类型决定。
29 void (*pfoo)(int, float) = foo;
30 pfoo(10, 20); // foo(int, float);
31 return 0;
32 }
~
- 函数重载匹配(编译器决定)
调用重载关系的函数时,编译器将根据实参与形参的匹配程度(内存),自动选择最优的版本。
当前g++编译器的一般匹配规则:
完全匹配 >= 常量转换 > 升级转换 > 降级转换 > 省略号匹配
1 #include <iostream>
2 using namespace std;
3
4 //char --> int ::升级转换(内存浪费)
5 void bar(int i)
6 {
7 cout <<" bar(1)"<< endl;
8 }
9 //char --> const char : 常量转换
10 void bar(const char c)
11 {
12 cout <<" bar(2)"<< endl;
13 }
14
15 //short(2 byte) --> char(1 byte) : 标准转换(降级转换)
16 void fun(char c)//char 1 byte
17 {
18 cout<<" fun(1) "<<endl;
19 }
20 //short(2 byte) --> int(4 byte) : 升级转换
21 void fun(int i)//int 4 byte
22 {
23 cout<<" fun(2) "<<endl;
24 }
25
26 //省略号匹配
27 void hum(int i, ...)//...可变长参数
28 {
29 cout<<" hum(1) "<<endl;
30 }
31
32 //double(8 byte) --> int(4 byte) : 降级转换
33 void hum(int i, int j)
34 {
35 cout<<" hum(2) "<<endl;
36 }
37
38
39 int main(int argc, char * argv[])
40 {
41 //常量转换优先级高于升级转换
42 char c = 'A';
43 bar(c);//bar(2)
44
45 //在数据转换时,数据的完整型优先级高于内存的使用
46 short s = 10;
47 fun(s);//fun(2)
48
49 //数据转换时:优先确定类型的转换
50 hum(10, 3.14);//hum(2)
51
52 return 0;
53 }
- 函数重载实现原理
C++编译器是通过对函数进行换名,将参数表信息整合到新的名字中,实现解决函数重载和名字冲突的问题。
笔试题:C++中 extern “C” 的作用?
答案:在C++函数声明的前面加入extern “C”, 要求C++编译器不对该函数换名,方便C程序直接调用。
注:extern “C” 声明的函数无法重载。
2 函数的哑元参数
- 定义
只有类型没有形参变量名的参数成为哑元
void func(int /*哑元*/){}
- 使用哑元的特征场景
1)兼容旧代码
eg: 算法库
void video_func(int a, int b){...}
使用者:
int mian(void)
{
video_func(10, 20);
}
----------------------
升级了算法库:void video_func(int a, int/*哑元*/){...}
使用者:
int main(void)
{
video_func(10, 20)
}
2)操作符重载中区分前后++/–
3.函数缺省参数(默认参数)
- 可以在声明函数时,为它的部分或全部参数指定缺省值,在调用该函数时,如果不给传递实参,就取缺省值作为相应形参的值。
eg:
void func(int a, int b = 0){}
func(100, 0);
func(100);//与上面的调用等价
- 缺省参数必须靠右,如果函数的一个参数带有缺省值,那么该函数的右侧所有参数都必须带有缺省值。
eg:
void func(int a = 0, int b){}//error
void func(int b, int a = 0){}//true
1 #include <iostream>
2 using namespace std;
3
4 void foo(int a, int b = 20, int c = 30)
5 {
6 cout<< a << " , " << b << " , " << c <<endl;
7 }
8
9 //缺省参数声明必须靠右写(靠右原则)
10 //error: default argument missing for parameter 2 of ‘void foo1(int, int, int)’
11 /*
12 void foo1(int a = 10, int b, int c = 30)
13 {
14 cout<< a << " , " << b << " , " << c <<endl;
15 }
16 */
17
18 int main(int argc ,char* argv[])
19 {
20 foo(1, 2, 3);// a 1, b 2, c 3;
21 foo(1, 2); // a 1, b 2, c 30;
22 foo(1); //a 1, b 20, c 30;
23 return 0;
24 }
- 缺省参数使用时注意重载时可能存在歧义问题;如果一个函数定义和声明分开,缺省参数写在函数声明部分,定义部分不写。
eg:
void func(缺省参数);//声明
void func(){...}//定义
1 #include <iostream>
2 using namespace std;
3
4 //函数声明
5 void foo(int a, int b = 20, int c = 30);
6 //void foo(int a, int = 20, int = 30);//true
7
8 //注意重载函数时的歧义错误
9 //void foo(int x){}
10
11 int main(int argc, char* argv[])
12 {
13 foo(1, 2, 3);// a 1, b 2, c 3;
14 foo(1, 2); // a 1, b 2, c 30;
15 foo(1); //a 1, b 20, c 30;
16 return 0;
17 }
18 //函数定义
19 void foo(int a, int b/*= 20*/, int c/* = 30*/)
20 {
21 cout<< a << " , " << b << " , " << c <<endl;
22 }
4 内联函数(inline*)
- 定义:
使用inline修饰的函数,表示这个函数是内联函数,编译器将会尝试做内联优化,减小函数调用的开销(空间换时间)。
笔试题:inline 关键字的作用?(定义) - 适用场景
1)多次调用小而简单的函数适合内联;
2)调用次数极少或者大而复杂的函数不适合内联;
3)递归函数不能内联;
注:内联只是一种建议而不是强制要求,一个函数能否内联优化主要取决于编译器,有些函数不加inline修改也会被编译器默认处理为内联优化,有些函数即使加了inline关键字也会被编译器忽略。