C++ 函数(二)函数重载/函数指针/函数匹配

main函数不能重载

重载函数

重载函数应该在形参数量或形参类型上有所不同

只有返回类型不同,也不是重载函数

注意注意:形参名字不同没有影响,类型别名为已存在类型提供一另一个名字,这也没有影响

typedef Phone Telno;
void lookup(const Phone&){}
void lookup(const Telno&){}
//上面的两个函数是同一函数,不是重载
//一个拥有顶层const的形参无法和没有的区分
void look(const Phone);
void look(Phone);

void look(Phone*);
void look(Phone* const);//以上两组函数每组都是一种函数,没有重载

//对于接收引用或指针的函数,对象是常量还是非常量对应的形参不同
void look(const Phone&);
void look(Phone&);

void look(const Phone*);
void look(Phone*);
//只能把const对象传给const形参,但是非常量可以转换成const,只不过会优先选择非常量版本的函数

const_cast

类型强制转换:
比如:

const string&shorting(const string&s1,const string&s2)
{
    return s1.size()>s2.size()?s1:s2;
}
//上面的函数返回const应用,且形参也是const的引用
//但是由于我们可以传入非常量实参,所以我们需要写一个非常量的版本
string& shorting(string&s1,string&s2){
	auto&r = shorting(const_cast<const string&>(s1),const_cast<const string&>(s2));
    return const_cast<string&>(r);
}

将实参强制转换为const的引用,调用const版本的函数,返回普通string&

作用域

不要使用局部函数声明,它会隐藏之前声明的函数,一旦编译器在当前作用域找到所需的名字,就会忽略外层作用域的同名实体

C++中,名字查找发生在类型检查前

void print(const string&);
void print(double);

void func()
{
	void print(int);
	print("value");//错误,被上一行隐藏了函数声明
}

语言特性

默认实参

一旦一个形参有了默认值,它之后的所有形参都必须有默认值

使用函数时省略参数即可

默认致残负责填补尾部实参,所以只能省略尾部的实参

string screen(size_type ht = 24,size_type wd = 80,char back = '');
//调用:
screen(,,'?');//错误
screen('?');//screen('?',80,'');,即使不报错,也不正确

函数允许多次声明

但是给定的作用域中一个形参只能被赋予一次默认实参

string screen(size_type,size_type,char = '');
string screen(size_type,size_type,char = '*');//错误
string screen(size_type ht = 24,size_type wd = 80,char);//添加默认实参
size_type wd = 80;
size_type ht = 80;
char def = '';
//局部变量不能用做默认实参
string screen(size_type = ht,size_type = wd,char = def);//添加默认实参
void f2()
{
	def = '#';//改变了默认值
	size_type wd = 180;//隐藏外层wd,但是没有改变screen的默认值
	window = screen();
}

内联,constexpr

内联函数,见C++ 类笔记

constexpr函数见 const(二)

函数匹配

(1)确定候选函数集:函数名以及其声明在调用点可见(被隐藏这种情况就不行了)

(2)考察实参:实参数量,实参类型(能转换成形参的类型也可以):可行函数

//下面两个函数与调用都匹配
void f(int);
void f(double,double = 3.14);
f(5.6);

(3)最佳匹配,上面的例子中第一个函数需要让实参从double转换为int,所以最佳匹配为第二个函数

多个形参更复杂:

需要有且只有一个可行函数满足:

该函数每个实参的匹配都不劣于其他可行函数需要的匹配

至少有一个实参的匹配优于其他可行函数提供的匹配

否则将会报错有二义性错误

void f(int,int);
void f(double,double);
f(42,4.13);
//两个参数各自对两个函数为精确匹配,所以报错

涉及类型转换影响函数最佳匹配:看书P219

函数指针

函数指针指向函数,函数的类型由返回类型和形参类型共同决定

bool length(const string&,const string&);
//此函数的类型:
bool(const string&,const string&);
//声明函数指针:
bool (*pf)(const string&,const string&);//用指针替换函数名

pf是指向函数的指针

()必须有,不然就是返回bool指针的函数

将函数名作为值使用:

pf = length;
pf = &length;//两者等价,&可选

//直接使用指向函数的指针调用函数,无需解引用指针
bool b1 = pf("yes","yes2");
bool b2 = (*pf)("yes","yes2");
bool b3 = length("yes","yes2");//三者等价

指向不同类型的函数指针之间没有转换规则

但是可以为函数指针赋值为nullptr或0

pf = 0;//不指向任何函数
//类型不匹配(形参类型或返回类型)
pf = cstringcompare;

如果定义重载函数的指针:

编译器会通过指针类型来决定选用哪个函数,指针类型必须和其中一个精确匹配

void ff(int*);
void ff(unsigned int);
void (*pf1)(unsigned int) = ff;//pf指向ff(unsigned int)
void (*pf2)(int) = ff;//形参列表都不匹配
void (*pf3)(int*) = ff;//返回类型不匹配

函数指针作为形参

void *(*start_routine) (void *)

上面的形参(函数指针),返回值为void* ,(*start_routine):start_routine为指向函数的指针,形参列表为 void*

参数为函数类型时,会自动转换为指向函数的指针

//等价:
void use(bool pf(const string&,const string&));
void use(bool (*pf)(const string&,const string&));

调用时,可以直接用函数名:
use(length);//自动转换为指向函数的指针
使用类型别名/decltype来简化
//func,func2都是函数类型
typedef bool func(const string&,const string&);
typedef decltype(length) func2;


//都是指向函数的指针
typedef bool (*func_p)(const string&,const string&);
typedef decltype(length) *func2_p;

void use(const string&&,func2_p);

返回指向函数的指针

使用类型别名

using pf = int (*)(int*,int);//f是指针类型
using f = int(int*,int);//函数类型
//返回类型不会自动转换为指针,所以必须显式的将返回类型指定为指针
f* f1(int);
pf f1(int);
int (*f1(int))(int*,int);//从内向外读,f1有形参列表(即为函数),前有*,f1返回一个指针,指针的类型本身也有形参列表,所以指针指向函数,函数的返回类型是int

//等价:
auto f1(int) -> int (*)(int*,int);//尾置类型

使用auto和decltype可以简化:

decltype(length)* getfun();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值