C++_Primer_5笔记----ch6(下)

函数

3.返回类型和return语句

return;
return expression;

无返回值的return语句用在返回类型是void的函数中。返回void的函数不要求非得有return语句,最后一句会隐式执行return。
强行令void函数返回其他类型的表达式会产生编译错误。

只要函数的返回类型不是void,则函数内的return语句必须返回一个值。

当函数返回局部变量时,意味着将返回值拷贝到调用点,返回一个副本。

不要返回局部对象的引用或指针
函数终止,局部变量的引用将指向不再有效的内存区域。

返回类类型的函数和调用运算符

//shortString返回较短的对象
auto sz = shortString(s1, s2).size();

引用返回左值
函数的返回类型决定函数调用是否是左值。
调用一个返回引用的函数得到左值。直白了说就是:函数调用可以放等号左边用。

char & get_val(string &str, string::size ix)
{
	return str[ix];
}
int main()
{
	string  s("a value");
	cout << s << endl;			//输出 a value
	get_val(s, 0) = "A";		//get_val当左值
	cout << s << endl;			//输出 A value
	return 0;
}

列表初始化返回值,返回值类型是类类型
C++11新标准规定,函数可以返回花括号包围的值的列表。

vector<string> process()
{
	if (expected.empty())
		return {};						//返回的vector对象为空
	else if (expected == actual)
		return {"functionX", "okey"};	//返回的vector对象用两个元素初始化
	else
		return {"functionX", expected, actual}};//返回的vector对象用三个元素初始化
}

主函数main的返回值
main函数可以没有return 语句,将隐式插入return 0;

返回数组指针
数组不能被拷贝,所以函数不能返回数组。可以返回数组的指针或引用。

  1. 使用别名
typedef int arrT[10];		//arrT的类型是含有10个整数的数组
using arrT = int[10];
arrT* func(int i);			//返回值的类型是指向含有10个整数的数组的指针
  1. 不使用别名
int (*func(int i)) [10];
  1. 使用尾置类型
    任何函数都可以使用尾置返回类型
    尾置返回类型跟在形参列表后面并以一个->符号开头
auto func(int i) -> int(*)[10];
  1. 使用decltype
int odd[] = {1,3,5,7,9};
int even[] = {0,2,4,6,8};
decltype(odd) *arrPtr(int i)
{
	return (i % 2) ? &odd : &even;		//返回一个指向数组的指针
}

4.函数重载

重载与const形参
顶层const不影响传入函数的对象

int look(int);
int look(const int);		//错误,重复声明了int look(int)

如果形参是指针或者引用,可以通过区分指向的常量对象还是非常量对象来实现函数重载。此时const是底层的。

int look(int&);
int look(const int&);		//新函数
int look(int *);			//新函数
int look(const int *);		//新函数

重载与const_cast
……
……

重载确定:编译器首先将调用的实参与重载集合中的每个函数的形参进行比较,根据比较结果决定到底调用哪个函数。

  1. 找到了最佳匹配,调用该函数。
  2. 找不到任何一个匹配,编译器发出匹配出错。
  3. 多于一个函数可以匹配,都不是最佳选择,二义性调用,出错。

重载与作用域
在局部作用域内声明函数,就隐藏了其他重载函数。

void print(const string &);
void print(double);
void foo(int ival)
{
	void print(int);		//在局部作用域声明,虽然不是好的选择
	print("Value: ");		//错误, print(const string &);被隐藏了
	print(ival);			//正确
	print(3.14);			//正确,调用print(int);,3.14转换为3。
}

5.特殊用途语言特性

  • 默认实参
  • 内联函数和constexpr函数
  • 调试帮助

默认实参

typedef strin::size_type sz;
string screen (sz ht = 24, sz wid = 80, char backgrnd = ' ');

可以为一个或多个形参提供默认值,上例每个形参都提供了默认值。
一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值。所以,使用默认值的形参放后面

string window;
window = screen();					//等价于 screen(24, 80, ' ');
window = screen(66);				//等价于 screen(66, 80, ' ');
window = screen(66, 256);			//  screen(66, 256, ' ');
window = screen(66, 256, '#');		//  screen(66, 256, '#');
window = screen(, , '?');					//错误,只能省略尾部实参

所以,使用默认值的形参放后面

给定的作用域内,一个形参只能被赋予一个默认实参,后续的声明只能为之前没有默认值的形参添加默认实参。该形参右侧的所有形参都必须有默认值。

string screen(sz, sz, char = ' ');
string screen(sz, sz, char = '*');			//错误,重复声明。一个形参只能被赋予一个默认实参
string screen(sz, sz = 80, char = '*');		//后续的声明只能为之前没有默认值的形参添加默认实参。该形参右侧的所有形参都必须有默认值。

局部变量不能作为默认实参。

内联函数和constexpr函数
调用函数包含一系列的工作:保存寄存器的值,并在返回时恢复;可能需要拷贝实参,程序转向一个新的位置继续执行。

内联函数可避免函数调用的开销。
inline
内联函数用于规模较小,流程直接,频繁调用的函数。

constexpr函数是指能用于常量表达式的函数。函数的返回值类型和所有的形参类型都是字面值类型,函数体中必须有且仅有一条return语句。

constexpr int new_sz() { return 42; }

内联函数和constexpr函数放在头文件里。

调试帮助

  • assert预处理宏
    assert宏定义在cassert头文件中。
assert(expr);		
//expr为假,assert输出信息并终止程序的执行。
//expr为真,assert什么也不做
  • NDEBUG
    assert 也依赖于NDEBUG,如果定义了NDEBUG,assert什么也不做。
    默认状态下没有定义NDEBUG,此时assert将执行运行时检查。

NDEBUG也可以自己编写条件调试代码。

#ifndef	NDEBUG
	//调试代码
#endif 

如果定义了NDEBUG,上述代码将被忽略。

6.函数匹配

一、确定候选函数
与被调函数同名,其声明在调用点可见。

二、选出可行函数
形参数量与实参数量相同
形参与实参类型相同,或实参类型能转换成形参的类型

三、选出最佳匹配
实参类型与形参类型与接近,匹配的越好。

7.函数指针

函数指针指向的是函数而非对象。

bool lengthCompare(const string &, const string &);		//函数声明

//指向一个函数,该函数的参数是两个const string的引用,返回值是bool
bool (*pf)(const string &, const string &);		//pf是函数指针

使用函数指针

pf = lengthCompare;
pf = &lengthCompare;			//二者等价

bool b1 = pf("hello", "goodbye");
bool b2 = (*pf)("hello", "goodbye");
bool b3 = lengthCompare("hello", "goodbye");		//三者等价

函数指针作为形参

//二者等价
void useBigger(const string &s1, const string &s2, bool pf(const string &, const string &));
void useBigger(const string &s1, const string &s2, bool (*pf)(const string &, const string &));

useBigger(s1, s2, lengthCompare);

函数指针作为返回值

//使用别名
using F = int (int *, int);		//F是函数类型,不是指针
using pF = int(*)(int *, int);	//pF是指针类型

pF f1(int);		//正确,返回值是函数指针类型		
F* f2(int);		//正确,返回值是函数指针类型
F f3(int);		//错误,不能返回一个函数

auto f4(int) -> int (*)(int*, int);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值