C++ primer(八)--内联函数 引用变量 引用传递函数参数 函数重载/模板/模板具体化

时间:2021-09-02 23:12:25

一、内联函数

    常规函数和内联函数的区别在于C++编译器如何将他们组合到程序中。编译过程的最终产品是可执行程序--由一组机器语言指令组成。运行程序时,操作系统将这些指令载入到计算机内存中,因此每条指令都有特定的内存地址。执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈,跳到标记函数起点的内存单元,执行函数代码,然后跳回到地址被保存的指令处。来回跳跃并记录跳跃位置意味着以前使用函数时,需要一定的开销。

    有了内联函数,编译器使用相应的函数代码替换函数调用。对于内联代码,程序无需跳到另一个位置处执行代码,再跳回来。内联函数的运行速度比常规函数快,但是代缴是需要占用更多的内存。

    使用这项特性,必须采取下述措施之一:

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

二、引用变量

    引用是已定义的变量的别名。主要作用是用作函数的参数。通过将引用作参数,函数将使用原始数据,而不是副本。因此,除了指针之外,引用也为函数处理大型结构提供了一种非常方便的途径。

  1)创建引用变量

    int rats;

    int & temp=rats;

    &不是地址运算符,而是类型标示符的一部分。就像声明中的char* 指的是指向char的指针一样,int &指的是指向int的引用。

    int rats=10;

    int & temp=rats;

    int * temp1=&rats;

    不过引用必须在声明引用变量时进行初始化。引用更接近const指针,必须在创建时进行初始化,一旦与某个变量关联起来,就效忠于它。

    int & temp=rats;

    实际是下述代码的伪装表示:

    int * const pr=&rats;

    对于上述的引用变量temp,如果一个变量再为int wang=10;

    temp=wang;

    最终的结果是:temp还是指向rats,只不过这个时候rats的值为10,地址仍旧为rats,并不是和wang的地址一样。

    再看下下面的代码:

int rats=101;
int * pt=&rats;
int & temp=*pt;
int bun=10;
pt=&bun;

将temp初始化为*pt使得temp指向rats,接下来将pt的指向改为bun,通过这种方式企图修改引用temp的值,是不可能的。
  2)将引用用作函数参数

    引用经常被用作函数参数,使得函数中的变量名称为调用程序中的变量的别名。这种传递参数的方法称为引用传递。按引用传递允许调用的函数能够访问函数中的变量。C语言只能按值传递,按值传递导致被调用函数使用调用程序的值的拷贝。还是看段代码自己领悟吧:

#include <iostream>
using namespace std;
double cube(double a)
{
a*=a*a;
return a;
}
double refcube(double & a)
{ a*=a*a;
return a;
}
int main()
{
double a=3;
cout<<cube(a);
cout<<"= cube of"<<a<<endl;
cout<<refcube(a);
cout<<"= refcube of "<<a<<endl;
return 0;
}

对于合适使用引用参数,可以根据自己思考的结果,使用引用参数的主要原因有两个:

  • 程序员能够修改调用函数中的数据对象。
  • 通过传递引用而不是整个数据对象,可以提高程序的运行速度。

三、函数重载

    函数多态(函数重载)能够使用多个同名的函数。其中函数多态和函数重载这两个术语是同一个概念。重载函数就像是有多个含义的动词。使用上下文确定要使用的重载函数版本。

    如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则他们的特征相同,而变量名是无关紧要的。C++允许定义名称相同的函数,条件是他们的特征标志不同。

四、函数模板

    函数模板允许以任意类型的方式来定义函数:

template <typename Anytype>
void swap(Anytype &a,Anytype &b)
{
Anytype temp;
temp=a;
a=b;
b=temp;
}

    第一行指出,要建立一个模板,并将类型命名为Anytype。关键字template和typename是必需的,除非可以使用关键字class代替typename。必须使用尖括号。类型名可以任意选择(这里为Anytype)。但是需要注意的就是,在自己写练习时,模板函数名不能使用swap,因为模板中也有这么一个模板。对于模板,也是可以重载的,重载的过程和原来一样。在模板显示实例化,可以通过一个例子来说明:

template <typename T>
T add(T a,T b)
{
return a+b;
}
.....
int m=6;
double x=10.2
cout<<Add<double>(x,m)<<endl;

上述例子就是显示实例化的例子。

  1)编译器选择使用哪个函数版本、

    对于函数重载、函数模板和函数模板重载,C++需要一个定义良好的策略,来决定为函数调用使用哪一个函数定义,尤其是有多个参数时。这个过程称为重载解析,大体步骤:

  • 创建候选函数列表。包括与被调用函数的名称相同的函数和模板函数
  • 使用候选函数列表创建可行函数列表。
  • 确定是否有最佳的可行函数。