一、形参带默认值的函数
说到形参带默认值的函数我们还是引用我们最常写的函数,并给出语句指令执行方式如下:
#include<iostream>
#include<string.h>
using namespace std;
int sum(int a, int b)
{
int temp = 0;
temp = a + b;
return temp;
}
int main()
{
int a = 10;
int b = 20;
int ret = sum(a, b);
cout << "ret:" << ret << endl;
return 0;
}
那么形参如何给实参传参数呢?以下是给出的几种传递方式,以及传参时应该注意的规则。
规则一:给默认值的时候,从右向左给
如下的方式是正确的
int sum(int a, int b=20)
{
int temp = 0;
temp = a + b;
return temp;
}
但是以下的方式就是错误的
int sum1(int a=10, int b )
{
int temp = 0;
temp = a + b;
return temp;
}
因为形参是从右向左压栈
规则二:相比于不传参数,传入参数的效率更高,因为少了move指令。
我们来看看,具体的语句指令
int ret = sum(a, b);的指令如下:
mov eax,dword ptr[ebp-8]
push eax
mov ecx,dword ptr[ebp-4]
push ecx
call sum
ret = sum(a);的指令调用如下:
push 14H
mov ecx,dword ptr[ebp-4]
push ecx
call sum
ret = sum2();的指令调用如下:它的效率等同于sum2(20,50)
push 14H
push 0AH
call sum
规则三:定义时可以给形参默认值,声明也可以给形参默认值。
申明的时候给默认值,函数体放在主函数后面
int sum3(int a = 10, int b = 20);
int main()
{
......
}
int sum3(int a, int b = 20)
{
int temp = 0;
temp = a + b;
return temp;
}
规则四:形参给默认值的时,不管是定义处给还是声明处给,形参默认值只能出现一次
如下的传递方式则是错误的,形参的默认值出现了两次
int sum3(int a = 10, int b = 20);
int sum3(int a , int b = 20);
但是如下的方式则是正确的,虽然第一个的形参赋值不是从右向左的但是第二个等式弥补了错误
int sum3(int a = 10, int b );
int sum3(int a, int b = 20);
二、inline内联函数
还是使用文章最开始的时候我们给出的代码进行分析。
首先我们来探讨一下
(1)什么是inline内联函数?
例如下面一段语句
int ret = sum(a+b);
此处有有函数调用的开销。包括参数压栈,函数栈帧的开辟和回退过程。
x+y 有两个指令 mov add mov 如果有10000次的x+y操作,那么将会有大量的时间用在了函数调用的开销上。
此时我们就可以使用内联函数。内联函数就是在编译过程中,就没有函数的调用开销,在函数的调用点直接把函数的代码进行展开处理(在符号表中也不用生成函数符号了)
(2)内联函数的处理过程:
就相当于在执行到int ret = sum(a, b);时,直接把sum函数展开,把a,b直接替换成了x,y变成了int ret = a+b;
(3)内联函数的注意点
- 但是不是所有的lnline都会被编译器处理成内联函数,比如说递归
递归的结束是在运行的时候看递归条件来决定什么时候结束,但是inline是编译器处理的,他是不执行指令的
- inline只是建议编译器把这个函数处理成内联函数
真正是否是内联函数还是编译器决定的 - debug版本inline函数不起作用,因为其需要调试,所以只在release版本才能出现
- 如果这个函数在短时间内会有大量调用且简单尽量设置成内联函数
三、函数重载
说到函数重载,我们首先给出下列代码
#include<iostream>
#include<typeinfo>
using namespace std;
bool compare(int a, int b)
{
cout << "compare_int_int" << endl;
return a > b;
}
bool compare(double a, double b)
{
cout << "compare_double_double" << endl;
return a > b;
}
bool compare(const char* a, const char* b)//compare_char*_char*
{
cout << "compare_char*_char*" << endl;
return strcmp(a ,b)>0;
}
int main()
{
compare(10, 20);
compare(10.0, 20.0);
compare("aaa","bbb");
return 0;
}
代码执行结果为:
细细观察上面几个函数,我们可以发现,他们的函数名相同,只是参数列表类型不同而已,由此引出我们函数重载的定义。
(1)什么是函数重载?
- 一组函数,函数名相同,参数列表的个数或者类型不同,那么这一组函数我们称之为函数重载
- 一组函数要称得上重载,一定是先处在同一个作用域当中
为了解释相同作用域是什么意思,我们举一个反例,在上面代码的基础上,我们把main函数改成这样:
int main()
{
bool compare(int a, int b);
compare(10, 20);
compare(10.0, 20.0);
compare("aaa","bbb");
return 0;
}
编译的时候我们会发现,这个程序是错误的。
因为当有这个函数声明的时候,大家都去一股脑的调用参数类型为int的函数了,因为他们在本地的局部作用域已经看到了这个声明。出现了类型不匹配的问题。
- 一组函数,函数名相同,参数列表也相同,仅仅是返回值不同。不叫重载
因为,在生成符号的时候与返回值是没有关系的
(2)c++为什么支持函数重载,但是c语言不支持
c++代码产生函数符号的时候,是函数名+参数列表类型
c代码产生函数符号的时候,函数名来决定(函数名相同就会产生链接错误