参数传递时,如果是引用类型,它将绑定到对应的实参上,否者,将实参的值拷贝后赋给形参。
引用可避免拷贝,如果不需要改变参数,最好定义成常量引用。
和其他初始化一样,当用实参初始化时会忽略顶层const,当形参有顶层const时,传给它常量对象或非常量对象都可以
我们可以用非常量初始化一个底层const对象,但反过来不行,同时一个普通的引用必须用同类型的对象初始化
尽量使用常量引用
可以使用数组引用形参f(int (&arr)[10]),来传输维度
对于多维数组,数组第二维的大小是组数类型的一部分,不能省略:
void print(int (*matrix)[10],int rowSize);
等价定义: void print(int matrix[ ][10],int rowSize);
int main(int argc,char *argv[]);
为了处理不同数量的参数,有两种方法,
如果所有的参数类型相同,可以传递一个,initializer_list的标准库类型
如果实参的类型不同,我们可以使用可变参数模板
initializer_list提供的操作:
initializer_list<T> lst; //默认初始化
initializer_list<T> {a,b,c...} //列表初始化
lst2=lst; lst2(lst); 拷贝后原始列表和副本共享元素
lst.size()
lst.begin()
lst.end()
initializer_list对象中的元素永远是常量
void error_msg(initializer_list<string> il);
void error_msg(ErrCode e,initializer_list<string> il);
省略符形参是为了便于c++程序访问某些特殊的c代码而设置的。
void foo(parm_lsit,...) parm_list是正常的参数类型
千万不要返回局部变量的指针或引用
引用返回的是左值,因此可这样写 get_val(s,0) = 'A'
可以返回列表,类似于初始化; return { }; return{"function","okay"};
main 的返回值在cstdlib中,EXIT_FAILURE,EXIT_SUCCESS;
因为数组不能拷贝,所以函数不能返回数组。不过可以返回数组的指针或数组的引用
typedef int arrT[10];等价于using arrT=int[10];
声明返回数组指针的函数
int (*func(int i))[10];
等价于,尾置返回类型 auto func(int i)-> int(*)[10];
int odd[]={1,3,5,7,9};
int even[]={0,2,4,6,8};
decltype(odd) *arrPtr(int i);
返回的是一个指向含有5个整数的数组的指针,decltype不负责把数组转换成指针
一个拥有顶层const的形参无法与另一个没有顶层const的形参区分开来
int lookup(phone); int lookup(const phone); 重复声明
int lookup(one*); int lookup(one * const); 重复声明
如果形参是指针或引用,区分其对象是const还是非const可以重载,此时是底层const
Record lookup(Account&);
Record lookup(const Account&); 可以重载
const对象不能转换成其他的类型,所以我们只能把const对象(或指向const的指针)传递const形参
相反,非常量可以转换成const,所以上述的两个函数都你作用于非常量和指向非常量对象的指针
当我们传递一个非常量,优先选用非常量版本函数
如果函数名字能区分并有一定意义 还是不要重载
可使用const_cast 来调用已有的函数实现const重载
c++名查找发生在类型检查之前,因此在局部中声明的名字会屏蔽之前的所以名字
函数可声明多次,后续声明只能为之前那些没有默认值得形参添加默认实参,而且该形参右侧的所有形参必须都有默认值
string screen(sz,sz,char=' ');
string screen(sz,sz,char = '*');// 重复声明
string screen(sz=3,sz=8,char);//正确,添加默认实参
局部变量不能作为默认实参。只要能转化成形参都可用。
对于默认实参求值过程发生在函数调用时。
sz wd=80;
char def=' ';
sz ht();
string screen(sxz = ht (),sz = wd ,char = def);
string window = screen(); //调用screen(ht(),80,' '),wd,def,ht的声明要出现在函数之外;
void f2()
{
def = '*';
sz wd= 100;
window = screen; //调用 screen(ht(),80,' *')
}
注意,在f2内改变了def,对scrren有影响,wd重新定义,屏蔽了外层wd,但是该局部变量与传递给screen的默认实参没有关系
内联函数
constexpr函数指的是用于常量表达式的的函数,函数的返回类型及其所有参数都得是字面值类型,而且必须有一条返回语句
constexpr函数调用时替换成其表达式的结果;,隐式的指定为内联。
constexpr函数除return外,还可以有别的语句,只要这些语句不执行任何操作,空语句,类型别名,uing声明
如果我们给constexpr函数的参数是常量表达式,返回的也是常量表达式,如果是非常量,放回的也是非常量
把内联函数和constexpr函数放在头文件中
assert ,在cassert中,#define NDEBUG 后assert不再起作用
void print(const int ia[ ],size_t size)
{
#ifndef NDEBUG
// _ _func_ _是编辑器定义的一个局部静态变量,用于存放函数的名字,输出当前调试的函数的名字,每个函数都有
cerr<<_ _func _ _<<":array size is "<<size<<endl;
#endif
}
_ _FILE__存放文件名的字符串的字母值。
_ _LINE_ _存放当前行号的整型字面值
_ _TIME_ _ 存放文件的编译时间的字符串字面值
_ _DATE_ _存放文件的编译日期的字符串字面值
调用重载函数时应尽量避免强制类型装换,如果确实需要,说明我们的设计形参集合不合理
为了确定最佳匹配,实参到形参转换的顺序;
精确匹配,包括以下情况:
实参类型和形参类型相同。
实参从数组类型或函数类型转换成对应的指针类型。
想实参添加顶层const或const实参中删除顶层const
通过const转换实现的匹配
通过类型提升实现的匹配
通过算术类型转换或指针转型实现的匹配;
同类类型转换实现的匹配。
给函数指针赋值,用函数名,该函数将自动转换成指针,也可以给函数名前加上&,两者等价
调用时无需提前解引用,函数可以做形参,它会自动转换成指针
typedef bool Func(const& string,const& string); typedef decltype(lengthcompare) Func2;
typedef bool(*Func)(const& string,const& string); typedef decltype(lengthcompare) *FuncP2;
使用Func2和FuncP2 一样;
必须把返回类型写成指针形式,编辑器不会自动转换
最简单的是使用别名,
using F = int(int* , int);///F是函数类型
using PF = int(*)(int* , int) //F是函数指针类型
PF f1(int);
F f1(int); //错误,要使用函数指针返回
F* f1(int);
直接声明 int (*f1(int))(int* , int);
尾置返回类型
auto f1(int) -> int (*) (int*,int);
当用decltype作用于某个函数时,它返回函数类型而非指针。所以我们要显示地加上* 。