C++ primer(八)--内联函数 引用变量 引用传递函数参数 函数重载/模板/模板具体化
一、内联函数
常规函数和内联函数的区别在于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++需要一个定义良好的策略,来决定为函数调用使用哪一个函数定义,尤其是有多个参数时。这个过程称为重载解析,大体步骤:
- 创建候选函数列表。包括与被调用函数的名称相同的函数和模板函数
- 使用候选函数列表创建可行函数列表。
- 确定是否有最佳的可行函数。