一、内联函数
1.1、函数的编译与运行
编译的最终产品是可执行文件-由一组机器语言指令组成。运行程序时,操作系统将这些指令载入到计算机的内存中(所以每条指令都有特定的内存地址),计算机逐步执行这些指令。函数的调用使得程序跳到另一个函数的地址,并在函数结束时返回,具体过程如下:
执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,,并将函数的参数复制到堆栈(内存块),跳到标记函数起点的内存单元,执行函数代码至完成(如果有返回值还需要将返回值放入到寄存器中)。然后跳回到地址被保存的指令处。
函数调用意味着地址的来回跳跃并记录跳跃的位置,这需要时间的开销。
1.2、内联函数的作用和实现
作用:提高程序运行速度。
使用:在函数的声明与定义前加上关键字inline。
实现:编译器将使用内联函数的代码替换函数的调用代码,此时,程序不需要跳跃到另一个位置处执行代码并跳回来,因此内联函数的运行速度比常规函数快,代价是占用了更多的内存。(以空间换时间,如果内联函数被调用多次,则相当于代码段的副本存在多处)
1.3、内联函数使用
1、内联函数代码执行时间应很短,而且要小于函数调用机制开销的时间,因此内联函数调用才能节省时间,尤其是内联函数经常被调用才能节省较多的时间。
2、内联函数不能递归。
3、类似与C语言的预处理语句#define来提供宏
二、引用与函数
2.1、引用是什么
引用是已定义的变量的别名(另一个名称)。
2.2、引用的作用
主要用途是用作函数的形参,通过将引用变量作为函数的参数,函数内将使用变量的原始数据,而不是副本。
2.3、引用的创建
C++使用&符号表示变量的地址,也可以用来声明引用变量。
int rats;
int & rodents = rats;
在此处的代码,&不是地址运算符,而是类型标识符的一部分,就像char*指的是指向char的指针,int&指的是指向int的引用。上述代码的引用声明允许两个变量相互替换,因为他们指向相同的内存单元和值。
特:声明引用时必须将其初始化,而不能像指针一样,先声明后赋值。此时接近于const指针,一旦与某个变量关联,就无法再变更,但是可以通过赋值语句修改值。
int * const ptr = &rats;
2.4、引用传递
引用被用作函数参数,使得函数中的变量名成为调用程序中变量的别名,这种传递参数的方式称为按引用传递 ,此时被调用的函数可以访问调用函数中的变量。区别于按值传递导致被调用函数只能使用调研程序的变量值的拷贝。
此处需要区分指针传递,指针修改指向变量的原始数据需要使用解除引用运算符*。
int swapr(int &a, int &b);
int swapr(int *a, int *b);
使用引用传递的原因有两个:
1、程序员能够修改函数中的数据对象。
2、通过传递引用而不是整个数据对象,可以提高程序的运行速度。(数据对象较大时)
2.5、常量引用
如果函数调用时,希望使用引用,但是不想函数内修改引用变量的信息,则应该使用const完成常量引用方式。但是引用不适合与基本的数据类型,而是当传递的数据比较大时,比如结构体或类,引用参数会更有用。
double refcube(const double &ra);
2.6、尽可能使用const
可以避免无意中修改数据的编程错误。并且尽可能用const代替#define,因为#define并不安全,不做检查只是替换。
2.7、引用作返回
避免返回函数终止时不再存在的内存单元引用,尤其是函数内的临时变量的引用。
如果函数要返回引用用于赋值,可以返回函数内的引用参数,或在函数内使用new来分配新的存储空间,并返回指向该内存空间的指针。
2.8、引用、指针、按值传递
传递值而不做修改时:
1、数据对象很小,如基本数据类型或小型结构,则按值传递
2、数据对象为数组。则使用指针,并将指针声明为指向const的指针
3、数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率,可以节省复制结构所需的时间和空间。
4、数据对象是类对象,则使用const引用,类设计的语义常常要求使用引用,需要记住类对象参数的标准方式是按引用传递。
需要修改调用函数中的数据时:
1、数据对象是内置数据类型,则使用指针。
2、数据对象是数组,则只能使用指针。
3、数据对象是结构,则使用引用或指针。
4、数据对象是类对象,则使用引用。
三、函数的默认参数
原则:对于有参数列表的函数,必须从右往左添加默认值,即要为某个参数设置默认值,则必须它右边的所有参数都带有默认值,不能跳过。
四、函数的重载
函数重载(多态)是C++上新加的特性。即可以使用多个同名的函数。多态或重载指的是多种形式,通过函数重载设计一系列函数,它们完成相同的工作,但是使用不同的参数列表。仅当函数基本上执行相同的任务,但使用不同形式的数据时,才应采用函数重载。
重载的关键信息-函数的参数列表(函数特征标),只有两个函数的参数数目和类型相同,且参数的排序顺序也相同,则称为特征标相同,其中变量名叫什么无所谓。
void sink(double & r1);
void sink(const double & r2);
void sink(double &&r3);
四、函数模板
4.1、什么是函数模板
即通用的函数描述(通用编程),使用过泛型来定义函数,其中的泛型可用具体的类型(如int 或 double)替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。
template <typename T>
void swap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
....
int i = 10, j = 20;
swap(i,j);
swap()函数接受了两个int参数,因此编译器生成该函数的int版本,也就是用int替换所有的T,得到下面的版本:
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
注意函数模板不能缩短可执行程序,调用多少种,最终就会有多少个独立的函数被定义,最终的代码内不包括任何模板,而只是包含了为程序生成的实际函数,模板的好处只是使得生成多个函数定义更简单,可靠。