C++

c++ function

function

Posted by Jow on August 8, 2019

目录

  1. 函数的参数
  2. 函数指针
  3. 内联函数
  4. 引用变量

基于范围的for循环

使用数组作为参数,我们传入的是数组的第一个值的地址,所以在定义形参的时候使用 int * arr和int arr[]是等效的。一般记住下面的等式:

1
2
3
4
5
6
arr[i] == *(arr + i);
&arr[i] == arr + i;
void fillArray[int arr[], int size);
void fillArray[int arr[size]); //不推荐
void fillArray(const int arr[], int size);
void fillAray(const int *beginArr, int *endArr);

使用数组作为参数将会,将数组的在内存中的地址传递过去,这不像基本数据类型,函数将使用变量的拷贝。传过去的值是原来的数组,这就意味着函数是可以改变原来的数组的。为将数组类型和元素个数告诉数组处理函数,请通过两个同的参数来传递它们,不用使用方括号的方式,即在形参中的括号中最好不要加入size。

为了保护数组不在调用函数中被修改,可以使用const修饰符来进行修饰。

在传递参数的时候也可以传递结构,可以用整个结果作为参数,还可以使用指针结构的指针作为参数,后者的好处就是传过去是地址的话耗费的时间和空间都将减少。

函数指针

如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。

  • 获取函数的地址:直接使用函数名即可
  • 声明函数指针:声明某种数据类型的指针时,必须制定指针指向的类型: int (*pf)(int)。(*pf)是函数,pf为函数指针。通常要声明指向特定类型的函数的指针,可以首先编写这种函数的原型,然后使用(*pf)替换函数名,pf就是这个函数的指针。
  • 使用指针调用函数:直接使用(*pf)(param)就可以调用函数,c++也允许像使用函数名那样使用pf(param),这两种方式都是允许的切符合规定的。 当指针对象过于复杂的时候我们可以使用typedef进行类型别命名,或者使用auto来命名。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    double pam(int);
    void estimate(int lines, double (*pf)(int));
    estimate(50, pam);//function call telling estiamte() to use pam();
    const double * f1(const double ar[], int n);
    const double * f2(const double [], int n);
    const double * f3(const double *, int n);
    const double * (*pa)(const double *,int n) = f1;
    const double *(*pa3[3])(const double *, int n) = {f1,f2,f3};
    const double *(*(*pd)[3]))(const double *, int) = &pa3;
    // auto pd = &pa3;
    typedef const double *(p_fun)(const double*,int)
    p_fun pa = f1.
    

使用typedef为现有类型创建别名,给变量定义一个易于记忆且意义明确的新名字,就像上面的p_fun。

内联函数

内联函数用内敛代码替换函数调用。要使用内敛函数:

  • 在函数声明前加上关键字inline();
  • 在函数定义前加上关键字inline();

内敛函数的好处是减少去堆栈中读取函数的过程,这样可以加快函数的运行速度。

引用变量

C++新增了一种复合类型-引用变量。引用是已定义的变量的别名。引用变量的主要用途是作为函数的形参。通过将引用变量用作参数,函数将使用原始数据,而不是其副本。在下例子中,&符号不是地址运算符,而是类型标识符的一部分。就像声明中的char*指的是指向char的指针一样,int&指向int的引用。上述引用声明允许rats和rodents互换-它们指向相同的值和内存单元。引用更接近const指针,必须在创建的时候进行初始化,一旦与某个变量关联起来,就将一直效忠于它。

1
2
3
int rats;
int &rodents = rats;// make rodents an alias for rats
int* const pr = &rats;

咋一看好像引用对象和指针有点类似,但是他们还是存在一些不同的,引用更接近const

  1. 引用对象在创建的时候就要初始化。
  2. 指针是一个变量,只不过变量存储的是一个地址,指向内存的一个存储单元,而引用跟原来的变量本质上还是一个东西,只不过变量的一个别名而已。
  3. 引用类型的变量不可以再被引用

引用经常被用作函数参数,使得函数中的变量名成为调用程序中的变量的别名。这种传递参数的方法称为按引用传递。按引用传递允许被调用的函数能够访问调用函数中的变量。下面的前两种可以交换调用函数中的值,最后一种按值传递不行。按引用传递和按值传递不同之处在于声明和定义函数的时候,按引用传递的形参是引用值。即原来变量的别名,交换别名的值,就相当于交换原来变量的值。

1
2
3
4
5
void swapr(int * a, int * b);
void swapp(int& a, int & b);
void swap( int a, int b);
swapr(a,b);
swap(&a,&b);

在c++中,如果实参与应用参数不匹配,c++将生成临时变量。如果函数调用的参数不是左值或与之相应的const引用参数的类型不匹配,则c++将创建烈性正确的匿名变量,将函数调用的参数的值传递给改匿名变量,并让参数来引用该变量。

  • 实参的类型正确,但不是左值。
  • 实参的类型不正确但可以转换为正确的类型。

左值参数可以被引用的数据对象,如变量、数组元素、结构成员、引用和解除引用的指针都是左值。非左值包括字面常量和包含多项的表达式。常规变量和const变量都可以视为左值,因为可以通过地址访问他们。但常规变量属于可以修改的左值,而const变量属于不可修改的左值。

在开发过程中应尽可能的使用cost:

  • 可以避免无意中修改数据的编程报错。
  • 使函数能够处理const和非const实参,否则将只能接受非const数据。
  • 使用const引用使函数能够正确并使用临时变量。