C++基础-函数

怎甘沉沦 提交于 2019-11-28 16:19:42

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);  // 显式实例化,编译器直接创建特定的实例
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!