2020年7月28/30/1日
第八章 函数探幽
1.本章节是C++相较于C多出的函数特性,包括内联函数、按引用传递变量、默认的参数值、函数重载(多态)以及模板函数。
2.内联函数:常规函数和内联函数之间的主要区别不在于编写方式,而在于C++编译器如何将它们组合到程序中。
编译过程的最终产品是可执行程序——由一组机器语言指令组成。运行程序时,操作系统将这些指令载入到计算机内存中,因此每条指令都有特定的内存地址。计算机随后将逐步执行这些指令。
对于内联代码,编译器将使用相应的函数代码替换函数调用,程序无需跳到另一个位置处执行代码,再跳回来。因此内联函数的运行速度比常规函数稍快。(以空间兑换时间)
3.要使用内联函数要采取的措施:
通常的做法是省略原型,将整个定义放在本应提供原型的地方。并在之前加上关键词inline
4.内联与宏的区别:宏不是通过传递参数实现的,而是通过文本替换来实现的,文本里的算术表达式往往会造成替换后的逻辑错误。
5.必须在声明引用变量时进行初始化。
更接近const指针,一旦与某个变量关联起来,将一直效忠于它。
int &rodents=rats;
int *const pr=&rats;
6.
变量类型不正确或者类型正确却没有名称的时候,编译器会生成一个临时匿名变量,并让ra指向它。这些临时变量只在函数调用期间存在,此后编译器便可以随意将其删除。
7.引用非常适合用于结构和类。确实,引入引用主要是为了用于这些类型的,而不是基本的内置类型。
8.ostream是基类,而ofstream是派生类。派生类继承了基类的方法。
9.对于带参数列表的函数,必须从右向左添加默认值。
默认参数并非编程方面的重大突破,而只是提供了一种便捷的方式。在设计类时你将发现,通过使用默认参数,可以减少要定义的析构函数、方法以及方法重载的数量。
10.函数重载/多态:关键是函数特征标(函数的参数列表),或称接口相同。
一些看起来彼此不同的特征标是不能共存的,比如编译器在检查函数特征标时,将把类型引用和类型本身视为同一个特征标。
匹配函数时并不区分非const和const变量。
函数重载时,编译器将根据实参来决定使用哪个原型,函数特征标为非const时,只与带非const参数的调用匹配,而带const的函数两者皆可。产生这种差别的原因时由于将非const值赋给const是合法的,反之是非法的。
11.C++不允许以单单不同返回值的方式重载函数。返回类型可以不同,但特征标必须不同。
12.void sink(double &r1) lvalue
void sank(const double &r2) lvalue&rvalue
void sunk(double && r3) rvalue
重载调用三种参数的函数时,将调用最匹配的版本
13.何时使用函数重载:
14.名称修饰/名称矫正:他根据函数原型中指定的形参类型对每个函数名进行加密。编译器将名称转化为不太好看的内部表示,来描述该接口。
long MyFunctionFoo(int,float)
?MyFunctionFoo@@YAXH
15.函数模板,通用的函数描述,使用泛型来定义函数。其中的泛型可用具体的类型(int或double)替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。有时也被称为通用编程。
函数模板功能允许以任意类型的方式来定义函数
template<typename AnyType>
void Swap(AnyType &a, AnyType &b)
{
AnyType temp;
temp=a;
a=b;
b=temp;
}
就很好用
对不同类型使用同一算法的函数,可使用模板
16.函数模板也可以依据接口的不同进行重载,并非所有的模板参数都必须是模板参数类型。
17.显式具体化
template<>void Swap<job>(job & ,job &);
编译器在选择原型时,非模板版本优先于显示具体化和模板版本。
不要用Swap()模板来生成函数定义,而应使用专门为int类型显式地定义的函数定义。
18.显式实例化
template void Swap<int>(int, int)
19.重载解析:对于函数重载、函数模板和函数模板重载,C++指定的策略。
1.通过名称匹配创建候选函数列表。
2.通过参数数目匹配创建新的可行函数列表。通过隐式转换序列继续筛选可行的函数。
3.确定是否有最佳的可行函数。
20.
21.完全匹配和最佳匹配
(1)完全匹配
如果有多个匹配的原型,则编译器将无法完成重载解析过程。没有最佳的可行函数,编译器将生成一条错误消息(ambiguous)
22.模板函数的发展:
关键字decltype
decltype(expression) var;
如果expression是一个函数调用,编译器通过查看函数的原型来获悉返回类型,而无需调用函数。
decltype((xx)) r2 = xx; r2 is double &
decltype(xx) w =xx; w is double