C++ PRIMER PLUS (8) 函数探幽
第八章 函数探幽
8.1 C++内联函数
内联函数的编译代码与其他程序代码「内联」起来了。也就是说编译器将使用相应的函数代码替换函数调用。对于内联代码,程序无需跳到另一个位置处执行代码,然后再跳回来。因此,内联函数的运行速度比常规函数快,但代价是需要占用更多的内存,因为编译后的可执行程序由一组机器指令组成。运行程序时,操作系统将这些指令载入到计算机内存中。
内联与宏:宏不能按值传递,比如将(i++)传给宏,只能进行文本复制,而不会计算其值。
8.2 引用变量
引用是已定义变量的别名,他们指向相同的值和内存单元。
声明引用时,必须将其初始化。
8.2.2 将引用用作函数参数
void swap( int &a, int &b);
swap(wallet1, wallet2);
相当于将形参a
和b
分别初始化为wallet1
和wallet2
。参数传递给接受引用参数时,实参应是一个变量,而非计算表达式,毕竟引用函数是实参的一个别名。
仅当参数为const
时,C++才允许这样做,C++将生成临时变量。
8.2.4 将引用用于结构
通常,返回机制将被复制到一个临时返回存储单元中,随后调用程序将访问该区域,然而,如果返回值是一个引用,则返回内容将直接复制到变量中,这样做效率更高。
返回引用时最重要的一点是应避免返回当函数终止时不再存在的内存单元引用。为了避免这种问题,可以返回一个作为参数传递给函数的引用或用new来分配新的存储空间。
为何将const用于引用返回类型?
返回引用为const意味着你不能使用返回的引用直接修改它指向的结构,如:
const xxx & function(xxx& temp)
{return temp;}
xxx ori;
xxx aim;
function(aim) = ori;// 不允许,但若无const,则可以
8.2.5 将引用用于类对象
8.2.6 对象,继承和引用
派生类继承了基类的方法。基类引用可以指向派生类对象,而无需强制类型转换,所以可以定义一个接受基类引用作为参数的函数,调用函数是,可以将基类对象作为参数,也可以将派生类对象作为参数。
8.2.7 何时使用引用参数
传递值而不做修改的函数:
- 程序员能够修改调用函数中的数据对象
- 通过传递引用而不是整个数据对象可以提高程序运行速度
- 如果数据对象很小,如内置数据类型或小型结构,则按值传递
- 如果对象时数组,则使用指针,因为这是唯一选择,并将指针声明为指向
const
的指针 - 如果数据对象是较大的结构,则使用
const
指针或const
引用,以提高程序效率。这样可以节省复制结构所需的时间和空间 - 如果数据对象是类对象,则使用
const
引用
修改调用函数中数据的函数:
- 如果数据对象是内置数据类型,则使用指针
- 如果数据对象是数组,则只能使用指针
- 如果数据对象是结构,则使用引用或指针
- 如果数据对象是类对象,则使用引用
8.3 默认参数
默认参数必须通过函数原型设置。
8.4 函数重载
在函数中,是特征标,而不是函数类型使得可以对函数进行重载。
8.5 函数模板
8.5.2 显示具体化
当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板
显示具体化原型:
template<> void swap<job>(job&, job&);//job是一个数据类型
1.第三代具体化
对于给定的函数名,可以有非模板函数、模板函数和显示具体化模板函数以及他们的重载版本;显示具体化的原型和定义应以template<>
打头,并通过名称来指出类型;
具体化将覆盖常规模板,而非模板函数将覆盖具体化和常规模板。
旧版的C++编译器在具体化时,函数前不加template<>
,如:
void swap<job>(job&, job&);
8.5.3 实例化和具体化
- 编译器使用模板为特定类型生成函数定义时,得到的是模板实例。
- 显示具体化句法是,声明所需种类——用
<>
符号指示类型,并在声明前加上关键字template
; - 显示实例化与显示具体化的区别在于,显示具体化的意思是"不要使用模板来生成函数定义,而用独立的、
专门的函数定义为显示地为特定类型的函数定义。而且显示具体化声明在关键字template
后包含<>
,而显示具体化没有。
8.5.4 编译器选择使用哪个函数版本
第一步:创建候选函数列表,其中包含与被调用函数的名称相同的模板函数
第二步:使用候选函数列表创建可行函数列表。
- 这些都是参数数目正确的函数,为此有一个隐式转换序列,其中包括实参类型与相应的形参类型完全匹配的情况。例如,使用一个
float
参数的函数调用可以将该参数转换为double
,从而与double
形参匹配,而模板可以为float
声场一个实例。
第三步:确定是否有最佳的可行函数。如果有,则使用它,否则该函数调用出错
从最佳到最差的顺序如下:
- 完全匹配,但常规函数优先于模板
- 提升转换(例如,
char
和shorts
自动转换为int
,float
自动转换为double
) - 标准转换(例如,
int
转换为char
,long
转换为double
) - 用户定义的转换,如类声明中定义的转换。
附:
Page.255:完全匹配和最佳匹配
Page.257:有多个参数的函数
第八章结束