C++ Primer读书笔记:6.3~6.7
来源:互联网 发布:苹果系统mac系统下载 编辑:程序博客网 时间:2024/04/30 00:59
6.3 返回类型和return语句
列表初始化返回值
c++11新标准规定,函数可以返回花括号包围的值得列表,此处的列表也用来对表示函数返回的临时变量进行初始化。
vector<string> process(){ string expected, actual; ... if(expected.empty()) return {}; else if(expected == actual) return {"function", "OK"};}
上述可以返回值序列的主要原因是,一个值序列可以隐式转换为vector对象,上面的返回值语句实际上是发生了一次隐式类型转换。
返回数组指针
因为指针不能被拷贝,所以函数不能返回数组,但是函数可以返回数组的指针或者引用。
return int (&a)[10];return int (*p)[10];
由于定义一个数组的指针或者引用比较繁琐,所以可以使用数组别名来简化程序。
typedef int intArr[10]; //定义intArr为类型别名,要注意此时数组的维度也是类型的一部分using intArr = int[10];
要想定义一个返回数组指针的函数,应该遵循以下形式
Type (*functon(parameter_list)[dimension]; int (*func(int i))[10];
要特别注意理解上述声明形式,func(int i)可以视为是返回值ret,所以上述式子看为int (*ret)[10],表明对返回值进行解引用得到的是一个10维的int数组,所以函数的返回值是一个指向十维int数组的指针。
在c++11中还有一种简化上述函数声明的方法,就是使用尾置返回类型:
auto func(int i)->int(*)[10]; //注意auto不可以省略
当然我们也可以使用decltype,
int add[] = {1,2,3,4,5}; decltype(add) *func(int i); //需要另外添加一个*声明符
使用decltype要特别注意的是,decltype并不会把数组类型或者函数类型转化为数组元素指针或者函数指针(这种转化发生在形参初始化以及函数返回值时),所以要想表示数组的指针必须另外加一个*声明符。
6.4函数重载
重载与const形参
一个拥有顶层const的形参无法与一个没有顶层const的形参区分开来
void lookup(int i);void lookup(const int i); //无法仅凭顶层const的不同与上边的同名函数重载,将造成重定义错误
另一方面,如果形参是一个指针或者引用,则可以通过底层const把两个函数区分开来
void lookup(int &i);void lookup(const int &i); //正确,可以1通过底层const来区分形参,此函数与上面的函数构成了重载函数
我们只能把const对象传递给const形参,而当我们传递非const对象时,将优先调用非const形参的函数版本。
cons_cast和重载
const_cast在重载函数的情景中最有用。
const string &shortString(const string&s1, const string&s2) //函数1{ return s1.size() <= s2.size() s1 : s2; //返回的是一个const对象的引用}string &shortString(string &s1, string &s2) //函数2{ auto &r = shortString(const_cast < const string& >(s1), const_cast < const string& >(s2)); return const_cast < string & >(r); //返回一个非const引用}
在函数2中r虽然是一个const string&,但是它实际上是绑定在一个非const对象上,所以将其转换为一个非const对象显然是安全的。
上面两个函数使得其即可以返回const引用,还可以返回非const的引用,而且还使得代码得到了重用(一个函数是用用另一个函数实现的),这多亏了const_cast的使用。
重载与作用域
如果我们在内层作用域中声明了名字,那么它将隐藏外层作用域中声明的同名实体,所以在不同作用域中无法重载函数。
在c++语言汇总,名字查找发生在类型检查之前,一旦在内存作用域中找到了名字,则查找将停止,而不会继续查找外层作用域的名字,所以重载函数集必须位于同一作用域中。
6.5特殊用途语言特性
默认实参
在给定的作用域中一个形参只能被赋予一次默认实参,换句话说,函数的后续声明只能为之前那些没有默认值的形参添加默认实参,而且该形参右侧的所有形参都必须有默认值。
void lookup(int i1, int i2, int i3, int i4 = 0); //设置了i4的默认参数void lookup(int i1, int i2, int i3, int i4 = 1); //错误,重新设置了i4的默认参数,造成编译错误void lookup(int i1, int i2 = 2, int i3, int i4); //错误,i3未设定默认值时,不可以给i2设定默认值void lookup(int i1, int i2, int i3 = 3, int i4); //正确
局部变量不能设定为默认值,除此之外,只要表达式的类型可以转换为形参所需的类型,该表达式就可以作为默认参数,
int i = 80; //i的声明必须在函数之外void lookup(int i1, int i2, int i3, int i4 = i); //正确
constexpr函数
constexpr函数是指能够用于常量表达式的函数,它的定义必须遵循以下几条规则:函数的返回值类型及所有形参的类型都必须是字面值类型(但不一定要求是字面值常量),而且函数体中必须有且仅有一条return 语句(要特别注意这最后一点)。
编译器在编译期会把对constexpr函数调用替换为其结果值,为了能在编译过程中随时展开,constexpr函数被隐式的定义为内联函数。
内联函数和constexpr函数通常定义在头文件中。
调试帮助
一些调试用的宏
NDEBUG与assert配合使用,进行断言。定义NDEBUG时,程序将不进行运行时检查,assert断言将没有作用。
还有一些宏如下:
__FILE__ //文件名__LINE__ //行号__TIME_ _ //编译时间__DATE__ //文件编译日期__func__ //函数名 (特别注意在vs中更名为__FUNCTION__)
6.6函数匹配
再函数确定最佳匹配过程中,实参到类型的转化划分为几个等级,集体排序如下:
- 实参类型与形参完全相同
- 实参从数组或者函数类型转化为对应的指针类型
- 通过const转换实现的匹配
- 通过类型提升实现的匹配
- 通过算数类型转化实现的匹配
通过类类型转换实现的匹配
类型提升:比如char,short类型提升为int类型,float类型提升为double类型。
算数转化:要注意,所有算数转换的级别都是一样的,比如int至unsigned int并不比int到double具有更高的优先级。
void look(unsigned int i){ cout << "int" << endl;}void look(double d){ cout << "double" << endl;}look(1); //错误,将造成二义性
6.7函数指针
当我们把函数名作为一个值使用时,该函数自动转换为指针。此外,我们还可以直接使用指向函数的指针调用该函数,无需提前解引用指针。
void lookup() {}void (* pf)() = nullptr; //定义了一个函数指针pf = lookup; //指针赋值pf = &lookup; //与上面的式子等价pf(); //通过函数指针调用函数(*pf)(); //正确,与上面的调用等价
在指向不同函数类型的指针间不存在转换规则,但是和往常一样,我们可以为一个函数指针赋一个nullptr。
重载函数的指针
当我们通过重载函数名为一个函数指针赋值时,指针类型必须与重载函数中某一个函数精确匹配:
void f(int); void f(double); void (*pf)(char) = f; //错误,无法找到精确匹配的重载函数 void (*pf)(int) = f; //正确
函数指针形参与返回值
虽然不能定义函数类型的形参,但是形参可以是指向函数类型的指针,此时实参可以为函数对象,它将会被隐式转换为函数指针。
另外函数的返回值类型也不可以是函数类型,但是可以是函数指针,函数指针作为返回值时,我们必须把函数的返回值类型写成指针形式,编译器不会吧函数返回类型当做是指针类型处理。
using F = int(int *, int);F f1(int); //错误,函数类型不可以作为返回值F *f1(int) //正确,返回值为int(*)(int *, int);int (*f1(int))(int *,int); //正确,与上述的声明等价
将auto与decltype用于函数指针类型
可以使用auto将函数的返回值尾置:
auto f1(int)->int(*)(int *,int); //推断出f1的类型
使用decltype推导函数类型时要注意,当其作用于函数时,它将返回函数类型而非指针类型,因为我们如果要声明指针类型需要显示的加上*
int add(int *pi, int i);decltype(add) *getFcn(const string &); //需要显示加上*
- C-PRIMER PLUS读书笔记
- C-PRIMER PLUS读书笔记
- C++Primer读书笔记(一)
- C Primer Plus 读书笔记
- C++Primer读书笔记(二)
- 写写C++Primer读书笔记
- C primer 读书笔记1
- C++Primer读书笔记
- C++Primer读书笔记 Al
- C++primer读书笔记
- c primer读书笔记 第一章
- C++primer读书笔记5
- c primer读书笔记
- 《c++primer》 读书笔记
- c++primer读书笔记
- 《C++Primer》读书笔记(3)
- 《C++Primer》读书笔记(4)
- 《C++Primer》读书笔记(5)
- Android——ListView与适配器
- java常用IO流集合用法模板
- 数据结构实验之串三:KMP应用
- 杭电-1875 畅通工程再续(Kruscal)
- poj 2485 Highways ( prim )
- C++ Primer读书笔记:6.3~6.7
- assests文件下读取csv文件和图片
- poj-Flip Game
- hdoj1541 stars 树状数组
- js笔记
- (多校第五场1012)HDU5792 World is Exploding(树状数组)
- 【杭电1863】畅通工程
- HDU 5792 World is Exploding 2016多校赛第五场 树状数组+容斥原理
- bzoj1070