C++ primer 5th .Chapter 6 函数(二) 读书笔记

C++ primer 5th .Chapter 6 函数(二) 读书笔记

6.4 函数重载

如果同一作用域内的几个函数名字相同但是形参列表不同,我们称之为重载函数。在调用时,编译器会根据传递的实参类型腿短想要的是哪个函数。

Tips:main函数无法重载

判断两个形参类型是否相异

int look(const int &);
int look(const int &num);

第二个给形参取了名字,但是不影响形参列表的内容。

重载和const形参

顶层const不影响传入函数的对象,一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开来。

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

int look(int*);
int look(int* const);//重复声明了int look(int*)

对于接受引用或指针的函数来说,对象是常量还是非常量对应的形参不同,此时const是底层的:

int look(int &); //函数作用于int对象的引用
int look(const int&);//新函数,作用于常量引用

int look(int*);//新函数作用于指向int的指针
int look(const int*);//作用于指向const int的指针

const_cast和重载

const string &shorterString(const &s1, const &s2)
{
	return s1.size() <= s2.size() ? s1 : s2;
}

这个函数的参数和返回值都是const string的引用。我们可以对两个非常量的实参调用这个函数但是返回值依然是const string引用。
可以使用const_cast让这个函数的实参不是常量的时候,得到的结果是一个普通的引用。

string &shorterString(string &s1, string &s2)
{
	auto &r = shorterString(const_cast<const string&>(s1),
const_cast<const string&>(s2));
	return const_cast<string&>(r)
}

这个函数首先将实参转换为对const的引用,然后调用了shorterString函数的const版本。const版本返回对const string的引用,这个引用事实上绑定在了某个初始的非常量实参上,所以可以安全的转回string&。

调用重载的函数

函数匹配是一个过程,在这个过程中我们把函数调用与一组重载函数中的某一个关联起来,函数匹配也叫作重载确定

有三种情况:1)最佳匹配 。2)无匹配。 3)二义性调用。

6.4.1 重载与作用域

如果我们在内层的作用域中声明名字,他将隐藏外层作用域中的同名实体。在不同的作用域中无法重载函数名

Tips:在C++语言中,名字查找发生在类型检查之前。

6.5 特殊用途语言特性

6.5.1 默认实参

一旦某个形参被赋予了默认值后,他后面的所有形参都必须有默认值。

//声明时设定默认值
string screen(size_t ht = 24, size_t wid = 80, char backgrnd = ' ' );

//在调用时只能省略尾部的实参
window = screen(, , '?'); //错误
window = screen('?'); //调用screen('?', 80, ' ');

Tips:尽量让不怎么使用默认值的形参出现在前面,而让那些经常使用默认值的形参出现在后面。

默认实参声明

string screen(size_t, size_t, char = ' ');
string screen(size_t, size_t, char = '*');//错误:重复声明
string screen(size_t = 24, size_t = 80, char );//正确:添加默认实参

默认实参初始值

局部变量不能作为默认实参。此外,只要表达式的类型能够转换成形参需要的类型,该表达式就能作为默认实参。

用作默认实参的名字在函数声明的作用域内解析,而这些名字的求值过程发生在函数调用时;

sz wd = 80;
char def = ' ' ;
sz ht();
string screen(size_t = ht(), size_t = wd, char = def);

void f2()
{
	def = '*'; //改变默认实参的值
	sz wd = 100; //隐藏了外层定义的wd,但是没有改变默认值
	window = screen(); //调用了screen(ht(), 80, ' ');
}

6.5.2 内联函数和constexpr函数

内联函数可以避免函数调用的开销,但是内联只是向编译器发送的一个请求,编译器可以选择忽略这个请求(如果编译器认为这个函数比较复杂)。

constexpr函数是指能用于常量表达式的函数。定义该函数的方法和其他函数类似,但是函数的返回类型以及所有形参的类型都得是字面值类型,而且函数体中必须有且只有一条return语句。

constexpr int new_sz() {return 42;}
constexpr int foo = new_sz(); //正确:foo是一个常量表达式

constexpr函数被隐式的指定为内联函数

Tips:constexpr函数不一定返回常量表达式。内联函数和constexpr函数通常定义在头文件中。

6.6函数匹配

函数匹配的第一步:是选定本次调用对应的重载函数集,集合中的函数称为候选函数。候选函数需要与被调用的函数同名,声明在调用点可见。

第二步考察本次调用提供的实参,选出能被这组实参调用的函数,称为可行函数。可行函数需要参数个数匹配,参数类型匹配,或者类型转换后能匹配。

第三步选取最佳匹配。

Tips:调用重载函数时应该尽量避免强制类型转换。

6.7 函数指针

函数指针指向的是函数而非对象,和其他指针一样,函数指针指向某种特定类型,函数的类型由他的返回类型和形参共同决定,与函数名无关。

bool lengthCompare(const string&, const string&);

该函数的类型是bool(const string&, const string&)。想要声明一个可以指向该函数的指针,只需要用指针替换函数名单即可:

//fp指向一个函数
bool (*fp)(const string&, const string&);//未初始化的函数指针

如果漏掉了*fp两端的括号

//声明一个名为fp的函数,该函数返回bool*
bool *fp(const string&, const string&);

使用函数指针

当把函数名作为一个值使用时,该函数自动转化为指针。

fp = lengthCompare;//fp指向lengthCompare函数
fp = &lengthCompare;//等价的赋值语句,取地址符是可选的

还可以用指向函数的指针来调用该函数,无需提前解引用指针:

bool b1 = fp("hello","good");//调用lengthCompare函数
bool b2 = (*fp)("hello","good");//一个等价调用
bool b1 = lengthCompare("hello","good");//另一个等价调用

在指向不同函数类型的指针之间不存在转换规则,但是可以为指针赋一个nullptr或者值为0的整型常量表达式,表示该指针没有指向任何函数。

重载函数的指针

使用重载函数指针时,编译器根据指针类型来选择哪个函数,指针类型必须与重载函数精确匹配

函数指针形参

和数组类似,虽然不能定义函数类型的形参,但是形参可以是指向函数的指针。

//第三个形参是函数类型,他会自动转换成指向函数的指针
void useBigger(const string &s1, const string &s2,
bool fp(const string&, const string&));
//等价声明:显示的将形参定义成指向函数的指针
void useBigger(const string &s1, const string &s2,
bool (*fp)(const string&, const string&));

返回指向函数的指针

在返回指向函数的指针时必须把返回类型写成指针形式,编译器不会自动将函数返回类型当成对应的指针类型处理。

想要声明一个返回函数指针的函数,最简单的办法是使用类型别名:

using F = int(int*, int);//F是函数类型
using PF = int(*)(int*, int); //PF是指针类型

PF f1(int);//正确:PF是指向函数的指针,f1返回指向函数的指针
F f1(int); //错误:F是函数类型,f1不能返回函数
F *f1(int);//正确:显示的指定返回类型是指向函数的指针
int (*f1(int))(int*, int);//直接声明f1

尾置类型写法: auto f1(int) -> int(*)(int*, int);

也可以使用auto和decltype:

size_t sumLength(const string&, const string&);
//根据形参的取值,getFcn函数返回指向sumLength的指针
decltype(sumLength) *getFcn(const string&);

使用decltype需要注意,他返回的是函数类型而不是指针,所以需要显示的加上*号。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值