形参
按值传递
值传递:
实参的副本作为形参的初始值,修改形参并不会影响实参
指针形参:相当于指针的拷贝,拷贝的是指针的值,同样不会影响实参指针,只会影响指针所指的对象 | 局部形参指针
按引用传递:
形参绑定传入的实参,作为实参的别名,不会发生拷贝
- 避免性能浪费:当传入大的类型(比如容器),应尽量使用引用避免拷贝
- 可以返回额外的信息:更改了传入的实参
const形参:
- 当作为顶层const,形参本身是const时,传入const || 非const都没有问题,但要注意,重载函数时会忽略顶层const,会造成多重定义错误
const 指针形参
- 当作为底层const,指向的对象是const,显示隐式-》初始化 & 类型转换,但反过来不行
- 当不需要修改指向的数据时,尽量使用对const 的指针,因为可接受范围广
const引用形参
- 尽量使用对const 的引用:
- 可接受范围广,只要可以转换为引用的类型就可以(非const, 字面值,表达式)
数组形参
- 数组的两个性质:
- 不允许拷贝,不能以拷贝数组的形式使用数组元素
- 使用数组,会转换为指向数组首元素的指针
- 指针形参:
- const type* = 等价const type[]
- 但是不知道数组的具体尺寸,可以通过下面方式:
- 对于c风格字符串const char[],以"\0"结尾
- 其他类型,可以传入数组首指针&尾后指针
- 显示传入数组大小,size实参
- 引用形参
- type (&name) [n]:表示name是一个绑定包含n个type类型数组的引用
- 形参的n个数必须=实参数组的元素个数
- 传递多维数组实参
- 以上都是一维数组,数组首指针指向第一个元素
- 而使用多维数组,会转换为指向首个数组元素的指针,也可以说指向指针的指针
- type (*name) [n] 等价于 type name[] [n]
- type (*name) [n]指向包含n个元素数组的形参指针name
可变形参
- 可以使用std::initializer_list<type> 模板类型作为形参:可以包含数量未知,但类型必须相同的实参
- 和vector的区别:元素永远时const,我们不能向vector一样改变元素的值
- 省略符形参:…3个点,必须位于形参列表的最后,表示函数参数数量不确定,
- 注意…这种方式不提供类型安全,程序员必须确保传递的参数类型和顺序与函数的实际期望相匹配,否则,可能导致未定义行为或运行时错误。
- 相对来说std::initializer_list提供了更强的类型安全性和灵活性
- 变长模板参数……
返回类型 & 返回值
返回类型要于返回值相同,或者可以隐式转换
无返回值:
返回类型为void,非必须有return;(终止当前的函数),因为会隐式执行return;也可以使用return;提前退出
有返回值:
返回类型非void,必须有return + 返回值
- 返回类型非&:返回值会拷贝,作为函数调用结果
- 返回类型为&:不会拷贝,直接作为函数调用结果
左值返回值:
- 当返回类型为&将返回左值,否则其余一律返回右值,作为左值一样可以同其他左值,作为赋值语句的左侧
列表返回值:……
- main()函数返回值:允许main在任何返回类型不提供返回值,因为将隐式return 0;0表示成功,其他表示失败
数组返回值:
- 根据数组的两个性质,发现只有两种返回方式,指针 || 引用
- 指针形式:
- type (*function(parameter_list) [n] ;
- 为了简化书写:
- 尾置返回:auto function(paramter_list) -> type(*)[n];
- 自动推断:decltype(数组name)* function(paramter_list);
类型别名
typedef:typedef + 类型 + 别名
using:using 别名 = 类型
注意::当使用指针引用常量时,不要展开别名,再重新组合,而是const修饰别名
自动推断:
auto类型:
- 让编译器自动通过初始值推断变量类型,所以auto声明的变量必须有初始值
- 因为一条声明语句仅能有一个基本数据类型,所以一条声明语句下,所有变量基本数据类型都一样
- 当引用作为初始值,推断的类型非引用,而是引用绑定对象的类型
- 会忽略顶层const,
decltype类型指示符
- 不会忽略顶层const
- 如果式*p解引用操作,将得到&类型
- 如果decltype中((变量))加了括号,得到的式&类型
函数重载
- 函数名相同但形参列表(数量 | 类型)不同,根据传递的实参类型推断使用哪个函数,这种泛型的好处,我们可以不修改调用的函数名,自动选择功能类似的函数调用
- 形参列表不相异:仅省略了形参名,类型为别名,顶层const(但底层const可以区分)
const_cast<type>(x)安全的转换为常量 或 非常量
函数匹配:
确定候选集(同名的且可访问),
确定可行函数(实参数量相同,类型相同或可以类型转换)
无匹配:否则以上情况不成立
最佳匹配:原则是实参形参类型越接近,优先级越高,(参数位置不参与优先级,而是所有实参匹配的总结果参与比较)
二义性:至少需要一个实参匹配优于其他匹配,当所有优先级都相等,则有二义性
实参匹配的级别:
精准匹配:类型完全相同
const转换的匹配
类型提升
算数类型转换
类类型转换
作用域:依旧遵守内部隐藏外层作用域同名函数
特殊语言特性_默认实参
-
为形参提供初始值,作为默认的实参,函数调用时,它可以省略,使用默认实参,也可以包含实参,改变默认初始值
-
默认形参一般出现在函数的后面
-
注意:一个作用域内只能提供一次默认实参
特殊语言特性_
内联函数 & constexpr
- 在返回类型前加inline关键字,可以避免函数调用的开销
- //
- 常量表达式:值在编译阶段计算,在运行期间不会改变
- 包括:字面值 / 常量表达式初始化的const对象
- const常量:在编译或运行阶段确定值,在运行期间不允许改变
- constexpr常量:constexpr声明的常量一定是const常量,初始化时必须用常量表达式初始化,也可以用constexpr函数初始化
- 相同点:都属于常量的声明,都必须在定义时初始化,
- 区别:constexpr常量必须在编译时就确定值,而且必须用常量表达式初始化
- constexpr函数:规定:形参和返回类型必须是字面值类型,函数体必须有一条return语句,函数体可以有除了return的语句,但必须保证在运行时不会更改。允许返回值为非常量
- constexpr作用:同const防止意外修改,也提高了运行时的效率
- 注意:内联函数和constexpr函数通常要定义在头文件中,它可以多次定义,不会有多重定义错误,但是它的多个定义必须完全一致
函数指针
-
函数指针:指向函数的指针,而非对象
-
声明:只需要替换函数名return type (*p) (parameter_list);
-
赋值:当函数名作为赋值语句的右侧(作为值),会自动转换为指针,可以赋值给函数指针,可省略&取地址符
-
调用:我们可以使用函数指针调用函数,p(c),可省略*解引用符
-
重载:如果函数指针指向重载函数,必须显示指出应该选用哪个函数,且必须有一个为精准匹配
-
函数形参:
-
与数组类似,如果想定义函数形参,需要函数指针,这样就可以把函数实参传递给函数指针形参,作为初始值
-
简化声明:利用typedef和decltype: typedef type (*p) (parameter_list); 等价 typedef decltype(函数) * 别名,(可省略*声明符)
-
函数返回值:
-
返回类型:return type (parameter_list type) ~= return type (*) (parameter_list type) ~= return type (*p(type)) (parameter_list type)由内而外阅读:p有type形参列表,所以是函数,返回类型为*,当使用是会自动转换为指针,p指针有形参列表,所以是函数指针,返回类型为 return type
-
还可以使用尾置返回auto p(type) ->type(*) (parameter_list type)同上,只是中间部分替换
-
使用自动推断:
-
decltype(明确知道的其他函数名)* function(parameter_list type),这和数组是一样的