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();