第八章,函数探幽
1.内联函数,拷贝一份函数副本,无需跳转。
缺点:占用更多内存;优点:节省时间。
执行时间<<函数调用时间,则优化调用时间,使用内联函数,声明前加inline
2.引用变量
(1)类型标识符的一部分,指向相同的值和内存单元。
(2)必须在声明时进行初始化,后续赋值与等号赋值相同。注意,就算是int rodents = pt也只能在声明时进行初始化,rodent永远指向声明时pt指向的内容,后续修改pt的指向,也不会修改rodents。
(3)传递引用,区别a、声明方式不同;b、指针版需要用解应用符*
(4)常量引用,不可修改。
(5)函数形参为const类型:a、实参类型正确,但不是左值;b、实参类型不正确,但可转换。此时都会生成临时变量,交换操作的话,会交换临时变量的值。
(6)左值,可被引用的对象,非左值:字面常量(引号的字符串除外),表达式
(7)const优点:a、避免修改;b、函数可处理const和非const的实参;c、使函数能正确生成并使用临时变量
(8)右值引用,可指向常量的引用&&
(9)使用引用用于结构
a、简化代码;
b、节省拷贝时间和内存;
c、返回引用的函数,可为左值,也可因为返回引用,从而重复调用。
d、省略拷贝,因此效率高。
e、返回一个作为参数传递给函数的引用,或者返回指向内存空间的指针。
f、使用const作用于返回值,返回的虽然为左值,但是不可修改,也算作右值。
(10)引用作用于类对象
a、string定义了char *到string的转换功能
b、基类引用可以指向派生类对象。接收基类引用为参数的函数,可以传递一个派生类对象为参数,也可以传递基类对象为参数。
c、ofstream为ostream的派生,因此fcout可传递为声明为ostream &的函数。
d、setf(ios_base::fixed)定点表示法,以定点模式显示浮点数
setf(ios_base::showpoint)强制显示小数点模式,即使小数为0.
precision()指定小数位数
width()下一次输出的字段宽度,仅下一个值有效,后续恢复默认。
ios_base:;fmtflags initial,用于存储显示格式。initial = os.setf(ios_base::fixed),之后可调用os.setf(initial)恢复。
3.默认参数
(1)函数传递默认参数,自右向左添加默认值。实参传递给形参时,为自左向右赋值,不能跳过任何参数。
(2)delete释放内存,但是不会将指针置空。
4.重载
(1)函数的参数数目,类型,排列顺序,为函数的特征标
(2)引用与变量本身为同一个特征标
(3)特征标导致可以重载,而不是返回值类型。不允许定义返回值类型不同,特征标相同的函数。
(4)非const类型赋值给const形参,是合法的,反之不合法。
(5)三种引用重载a、void staff(double &r1)匹配左值引用。b、void staff(const double &r2)匹配可修改的左值参数,const左值参数,右值参数。c、void staff(double &&r3)匹配右值参数。编译器寻找最匹配的调用。
(6)通过默认参数来实现重载目的,不可取,会报错编译不通过。
5.函数模板
(1)定义
template
void swap(T &a, T &b)
{
}
(2)typename可被class代替
(3)模板重载,基础类型重载。T为数组,指针,结构需小心,可能不成立。a、重载运算符,例如±<>;b、特定类型提供具体化模板定义
(4)显式具体化
a、函数名,可有非模板函数,模板函数和显式具体化模板函数以及它们的重载版本
b、显式具体化的原型和定义以template<>大头,通过名称来指出类型
c、非模板函数>具体化>常规模板
8.5.3 显式具体化
template <class T>
void Swap(T &a, T &b);
template <>void Swap<job>(job &a, job &b);
//template <>void Swap(job &a, job &b);也可以省略job
8.5.4 实例化和具体化
1.函数模板本身并不会生成函数定义,仅用于生成函数定义的方案。
2.编译器使用模板为特定类型生成函数定义时,得到的是模板实例。
3.模板并非函数定义,但使用int的模板实例,是函数定义。——隐式实例化。
4.显示实例化:
template void Swap<int>(int, int);
意义:使用Swap模板生成int类型的函数定义。
5.与显式具体化区别,显式具体化:不使用Swap模板生成函数定义,应使用专门为int类型显式地定义的函数定义。
6.警告:在同一个文件中,使用同一种类型的显式实例化和显式具体化,报错。
8.5.5 重载解析
1.编译器选择使用哪个函数版本:重载解析
2.过程:
a、创建候选函数列表
b、使用候选函数列表创建可行函数列表
c、确定是否有最佳可行函数
d、整数类型不可被隐式转换为指针类型。
f、最佳到最差顺序:1)完全匹配,常规函数优先于模板;2)提升转换,char和shorts转为int,float转为double;3)标准转换,int转为char,long转为double;4)用户定义的转换,类声明中定义的转换。
3、完全匹配与最佳匹配:1)指向非const数据的指针和引用,优先与非const指针和引用参数匹配;2)非模板函数优先于模板函数;3)都为模板函数,较具体的优先。显式具体化优先于模板隐式生成的具体化。最具体,指编译器推断哪种类型执行的转换最少(运行中执行的转换,编译时被解释的更具体)。
4.调用时指定,例如lesser<>(m,n)需调用模板函数,或lesser(m,n)显式实例化,用int代替T,强制转换形参。
5.多个参数的函数,编译器考虑所有参数匹配的情况。所有参数的匹配都必须不比其他函数差,同时至少一个参数的匹配程度更高。
6.发展:
a、模板内类型不确定,decltype关键字,decltype(x) y,令y与x的类型相同
b、decltype确定类型,编译器遍历核对表:
1)decltype(expression) var,expression没有用括号引起的标识符,var类型与标识符类型相同;
2)expression为函数调用,var为与函数返回值类型相同,但不会调用该函数;
3)expression为左值,var为其指向类型的引用。
4)前3种都不满足,则与expression类型相同。例如:表达式,例如decltype(x+y) xpy;
7.特例:
针对1)与3)做如下特例
double xx = 4.4;
decltype ((xx)) xpy = xx;//为xx的引用,xpy类型为double &
decltype(xx) w = xx;//与xx类型相同,为double
8.C11后置返回类型
声明函数时无法知道类型
template<class T1, class T2>
?type? gt(T1 x, T2 y)//x与y为域内变量,前置声明时不可使用
{
return x + y;
}
可采用auto后置
auto gt(T1 x, T2 y) -> decltype(x + y)//返回类型与x+y相同
//x与y为域内变量,后置返回类型,可使用。