内联函数
函数前面加inline就是内联函数:
内联函数会直接代替函数调用,出现在程序当中,不会有函数调用的过程。
内联函数的函数原型和函数定义放在一起,通常只有一行。
内联函数以值进行调用和返回。与C的宏定义不一样,C宏定义是原封不动的将表达式等放在宏的地方。
引用变量(伪装指针)
引用要求在定义的时候初始化
引用变量等价于:
int &a = rats;
int * const ps = &rats;
a与*ps相同
特殊操作:(可以作用于指针,但是不能用在表达式上)
int rats;
int *ps = &rats;
int &a = *ps;
// 此时a也是rats的引用
引用传递用于结构和类。不使用在基本变量上。
可以使用const double &a = b;保证引用不会修改原始值。
临时变量生成条件:(临时变量在函数结束的时候释放)
- 函数使用引用传递
- const引用(const引用保证不修改原值,因为临时变量不会对原值产生影响)
- 1.类型正确的非左值 2.类型不正确的左值。
临时变量和值传递操作相同,所以有的编译器会进制使用临时变量。
左值:可以引用的量:变量,数组元素,结构成员,指针,解引用指针。有地址
右值:字面值(除了字符串字面值),表达式。没有地址
尽量使用const的原因:
- const让实参既可以是const也可以是非const
- 保证数据不会被随意更改
- 可以使用临时变量
右值引用:应用在语义移动中。int && a;
函数的返回引用操作:返回的引用最好是输入到函数当中的引用。
常规函数的返回值是右值。
const string引用可以传递C风格字符串。
类对象的引用:ofstream是ostream的派生类。ostream是基类。
使用基类的引用设置函数参数:可以引用派生类和基类。
cout.setf(ios_base::fixed,ios_base::showpoint)
fixed是定点表示
showpoint是小数点后的0显示出来
cout.precision() // 小数点后,有效位数
ios_base::fmtflags 一种类型cout.setf()的返回类型,可以保存之前所有的setf配置,用于恢复
一个建议:
基础类型值传送,如果需要修改。使用指针
数组一定使用指针
结构使用指针或引用
类对象使用引用
默认参数放置在函数原型的定义当中。(实参从左到右依次赋值,默认参数从右向左依次给值)。
函数重载和函数多态一个意思:
多态指函数具有多个形态。重载是指有多个同名的函数。
函数重载:函数与函数之间的区分是特征标(即函数的参数列表)。
对于函数重载:
- int a和int &a等价
- const和非const带有指针和引用时有区别
对于const和非const优先匹配完全相同的情况。
对于unsigned int 和 int, long,long long之间没有远近,所以会出现二义性。
函数重载:只有在实现相同操作但是对于不同数据类型的时候,使用函数重载。
名称修饰,名称矫正:是针对编译器而言的一种变形,利于编译器识别不同的重载函数。
泛型编程也可称为通用性编程,其特性可以叫做参数化类型。
模板经常放在头文件当中:使用时调用头文件。
泛型编程:也有原型,定义,调用(生成)
template <typename T>
void swap(T &a,T &b);
// 原型
template <typename T>
void swap(T &a,T &b)
{
}
// 定义
swap(a,b);
// 使用
模板并不会被加入到可执行程序中,只有生成的函数在程序中。
对于swap交换操作:对于数组无法实现。(针对类似的问题)提出了显示具体化。得到具体化函数:
template<> void swap(job &a,job &b);
// job是一个结构
优先级:常规函数,具体化函数,模板函数.
实例化和显示具体化:
显示实例化和隐式实例化,显示具体化都是具体化。因为他们都生成了函数定义。
由于模板本身并不是定义,只有当调用的时候,编译器才会生成定义,这时是一个实例化的过程。但是是一种隐式实例化。
显示实例化:template void swap<int>(int ,int)
swap<double>(a,b)
显示具体化:template<> void swap<int>(int,int)
template<> void swap(int,int)
函数参数中:类型和非const引用不能强制转化。
重载解析:判断函数的优先级。
1.找到参数个数相同的函数或模板
2.去除类型不符合要求的。(强制转换可以也行)
3.按标准寻找。
- 完全匹配(常规>具体化模板>模板)不考虑const。
- 提升转换(short,char->int,float->double)
- 标准转换(int->char,long->double)
- 用户自定义转换
等价的情况,符合完全匹配要求但是参数类型不同的情况:1+3:1数组的情况。3是否有const,是否有volatile,是否有&引用.
只有两种情况完全匹配不会产生二义性ambiguous:
1.const起到区分作用只有当:指针和引用时成立
2.一个是模板函数,一个是常规函数,一个是显示具体化函数或者两个模板函数。(带有模板函数的情况,找出最具体的模板)
找最具体模板的规则:函数模板的部分排序规则。
通过调用方法来选择最优的匹配情况:
swap<>(a,b) <>暗示使用模板
swap<int> (a,b)显示实例化也是用模板
对于多参数的函数:如果一个比另一个强:则必须所有的参数匹配程度不低于另一个,且有一个比另一个高,此时才能说明一个比另一个更匹配。
针对以下问题:
template <typename T1,typename T2>
void swap(T1 x, T2 y)
{
xps = x + y;
} // xps的类型无法判断
int x, double y 则是double
short x,char y 则是int
解决方法:使用decltype(x+y) xps
decltype(expression)判断方法:1.单独的标识符,则与表示符类型相同。2.函数返回则与返回类型相同。
3.如果是左值,则左值类型的引用 4.都不满足则与expression同类型
问题2:
???? swap(T1 x, T2 y)
{
return x + y;
}
// 此时由于函数的返回值位置未定义x和y,不能使用decltype
// 引入后置返回类型
auro swap(T1 x, T2 y) -> decltype( x + y)
总结:重载解析:
1. 确定有没有自定义要求
2. 找到匹配的函数,利用函数的4个标准判决。
3. 找到匹配的模板,利用模板的部分排序规则实现