1. 函数简介
1.1 函数参数与参数传递
在C++语言中函数有两种传参的方式: 传值和传址。
以传值方式, 在函数调用过程中会生成临时变量用形参代替,并把实参的值传递给新分配的临时变量即形参。 但在函数调用结束后,实参不会跟随形参而改变。 如果要改变实参的值, 只能通过指针传递。如果函数是“只读函数”,为了防止数据/地址传递增加破坏数据的风险,需要在形参中增加const标识符来解决。
1.2 函数的递归
递归常用于重复性的程序当中。在递归中,每次递归调用都会创建自己的一套变量,保存在不同的地址空间当中。如下所示,可以用栈的入栈和出栈来表示递归。
void countdown(int n){
cout<<"Counting down ..."<<n<<" (Address at "<<&n<<")"<<endl;
if(n>0)
countdown(n-1);
cout<<n<<" Up"<<" (Address at "<<&n<<")"<<endl;
}
int main(){
countdown(5); //递归调用
}
该递归的运行结果为:
1.3 内联函数 inline
函数的调用在执行时,虽然可以减少可执行程序的体积,但也会带来程序运行时间上的开销。但是,如果一个函数内部没有几条语句,执行时间本来就非常短,那么这个函数调用产生的额外开销和函数本身执行的时间相比,就显得不能忽略了。
当编译器处理调用内联函数的语句时,不会将该语句编译成函数调用的指令,而是直接将整个函数体的代码插人调用语句处,就像整个函数体在调用处被重写了一遍一样。
内联函数 (inline) 与宏 (#define) 的区别
内联函数是通过参数的传递实现的,而宏定义是通过文本的替换实现。#define SQUARE(X) X*X //宏定义 #define SQUARE1(X) ((X)*(X)) //宏定义 inline double square(double x){ //内联函数 return x*x; } int main(){ cout<<square(5.0+3.0)<<endl; // (5.0+3.0)*(5.0*3.0) 输出结果为64 cout<<SQUARE(5.0+3.0)<<endl; // 5.0+3.0*5.0+3.0 输出结果为23 cout<<SQUARE1(5.0+3.0)<<endl; // ((5.0+3.0)*(5.0+3.0)) 输出结果为64 }
1.4 函数默认参数
默认参数是指当函数调用中省略了实参时自动使用的一个值。函数参数默认值设置必须通过函数原型进行设置,且带参数函数必须从右向左添加默认值。
char *left(const char *str,int n=1); // √ 函数原型,带参数函数必须从右向左添加默认值
char *left(const char *str,int m=1,int j); // × 从右向左添加默认值,不能跳过任何参数
char *left(const char *str,int m=1,int j=2); // √
left("theory",3); //函数调用,3将覆盖默认值
left("theory"); //函数调用,使用原型默认参数
1.5 函数重载
函数重载是指可以有多个同名的函数,根据上下文来确定要使用的重载函数的版本。函数重载是根据函数的参数列表(函数特征标)而不是根据函数类型。两个函数的参数数目和类型相同,同时参数的排序也相同时,他们的特征标也相同。其中类型引用和类型本身视为同一个特征标。
void staff(double & rs);
void staff(const double & rcs); //函数重载
long gronk(int n,float m) ;
double gronk(int n, float m); //不是函数重载
当函数基本上执行相同的任务,但使用不同形式的数据时,才应采用函数重载。如果两个重载函数,只是参数的个数不同,类型相同,则可以使用一个带默认参数的函数要简单一些。
char *left(const char *str,int n); 使用默认参数
char *left(const char *str); ========> char *left(const char *str,int n=1);
1.6 函数模板
函数模板允许以泛型的方式编写程序。函数模板不能缩短可执行程序,最终的代码不包含任何模板。编译器使用模板为特定类型生成函数定义得到的是模板的实例,模板并非函数的定义,使用模板实例是函数定义。模板的实例分为显式实例化和隐式实例化。当模板显式实例化时的参数类型不同时,可强制类型转换。
模板--->模板实例---->函数定义
template <typename T> //template和typename 为关键字,T为任意名称
void Swap(T &a, T &b);
void Swap(T *a, T *b,int n); //函数模板原型
template <typename T> //函数模板定义 template和typename 为关键字,T为任意名称
void Swap(T &a, T &b){
T temp;
temp=a;
a=b;
b=temp;
}
void Swap(T *a, T *b,int n){ //函数模板的重载
T temp;
for(int i=0;i<n;i++){
temp=a[i];
a[i]=b[i];
b[i]=temp;
}
}
int main(){
int aa=13,bb=19; //函数模板可以代入不同类型的数据
double daa=1.3,dbb=1.9;
Swap(aa,bb); // aa=19,bb=13; //隐式实例化
Swap<double>(daa,dbb); // 显式实例化,编译器直接创建特定的实例
}
来源:https://blog.csdn.net/weixin_42963969/article/details/100067341