学习语言都是比较枯燥的,不过不学会语言知识,直接看代码确实不好。今天继续c++第二天
2.1 内联函数
c++的内联函数和c的一样,本来不想写的,不过当做一次复习吧。
特点:
- 内联函数声明时inline关键字必须和函数定义结合在一起
- 编译器直接将函数体插入到函数调用的地方
- 内联函数没有其他函数调用时的开销(压栈、跳转、返回)
- 内联函数是一种特殊的函数,具有普通函数的特征。(可以检查参数,返回值等)
- 内联函数由编译器,直接将编译后的函数体插入调用的地方,宏代码片段 由预处理器处理,进行简单的文本替换,没有任何编译过程。
- C++中内联编译的限制
不能存在任何形式的循环语句。
不能存在过多的条件判断语句。
函数体不能过于庞大。
不能对函数进行取址操作
函数内联声明必须在调用语句之前 - 当函数体的执行开销远大于压栈,跳转和返回所用的开销时,那么内联将无意义。
来自《黑马程序员C++课程》
2.2 函数默认参数和占位参数
c++中函数是支持默认参数的
int get_area(int len, int width, int height)
{
return len * width * height;
}
int get_area2(int len = 10, int width = 20, int height = 30)
{
return len * width * height;
}
int main(int argc, char **argv)
{
cout << "hello c++ " << my_spaceA::my_spaceB::haha << endl;
int area = 0;
area = get_area(10, 20, 30);
printf("area = %d\n", area);
area = get_area2();
printf("area = %d\n", area);
area = get_area2(20, 30, 40);
printf("area = %d\n", area);
return 0;
}
函数的默认参数就是在函数的形参加个等号=什么,如果函数有默认值的时候,传参的时候可以不传参数的,如果我们传入了参数的话,函数就会用我们传入的参数,而不用默认值。
如果某个参数是默认参数,那么它后面的参数都要是默认参数,默认参数是从右到左的,因为填参数的时候是从左到右的,这样才不冲突。
这样是正确的:
int get_area2(int len, int width = 20, int height = 30);
int get_area2(int len, int width , int height = 30);
这样就是错误的:
int get_area2(int len = 24, int width , int height);
占位参数:
占位参数只有参数类型的声明,没有参数名的声明
一般情况下,函数是无法使用占位参数的
int get_area(int len, int width, int height, int)
{
return len * width * height;
}
//最后一个参数int 就是占位参数
给函数传参的时候,也需要传4个参数:
get_area(10, 20, 30, 40)
感觉有点难受,传入40也没啥用,体验一下默认参数+占位参数
int get_area(int len, int width, int height, int = 0)
{
return len * width * height;
}
这样传参就是3个参数和4个参数都可以的,具体用法,有待以后学习。
2.3 函数重载
C++ 不允许变量重名,但是允许多个函数取相同的名字,只要参数表不同即可,这叫作函数的重载(读“虫载”,不读“众载”,其英文是 overload)。重载就是装载多种东西的意思,即同一个事物能完成不同功能。
2.3.1 重载的规则
- 函数名相同
- 参数个数不同,参数的类型不同,参数顺序不同,均可构成重载
- 返回值类型不同不可以构成重载
例子:
2.3.2 调用准则
1.严格匹配,找到则调用
2.通过隐式转换寻求一个匹配,找到则调用。
3.函数重载的时候,不要用默认参数,使用不当会引起冲突
int get_area(int len, int width, int height)
{
return len * width * height;
}
还是上面的函数,我调用的时候:
area = get_area(10, 20, 30);
printf("area = %d\n", area);
area = get_area('a', 20, 30);
printf("area = %d\n", area);
这两个都可以匹配的上
2.3.3 重载底层实现
c++利用了name mangling(倾轧)技术,来改变函数名,区分参数不同的同名函数。
实现原理用vcifld表示void char int float long double及其引用。
void func(char a) //func_c(char a)
void func(char a, int b, double c) //func_cid(char a, int b, double c)
我们用的时候可以写函数名一样的重载,但是底层还是自己转换成不同名字的,我觉得c语言也可以利用这种命名方式。
2.4 函数重载和函数指针
既然函数可以重载,函数指针在赋值的时候会不会有问题?
显然是不会的,实际上在给函数指针赋值的时候,是会发生函数重载匹配的,如果能匹配上指针,这个指针的地址就固定了,不能在重载其他函数了。所以在调用的时候,调用的函数也固定了。
int get_area(int len, int width, int height)
{
printf("int int int\n");
return len * width * height;
}
int get_area(int len, int width, int height, int aa)
{
printf("char int int\n");
return (*len) * width * height;
}
main函数:
int main(int argc, char **argv)
{
cout << "hello c++ " << my_spaceA::my_spaceB::haha << endl;
int area = 0;
int (*areap)(int, int, int) = get_area;
areap(10, 20, 30); //这个是ok的
areap(10, 20, 30, 40); //这个是编译不过的
return 0;
}