一, 函数重载
普通函数重载的关键是参数列表 --- 也称函数特征标. 函数参数中有以下情况可以出现重载:
1, 形参个数不同
2, 形参的类型不同
3, 形参的类型和个数都不同
const 形参和函数重载
重载无法区分 const 和非 const
首先分清楚什么是顶层 const, 什么是底层 const
前提是有一个指针或是引用, 指向一个数据, 顶层 const 表示该指针不能改变(不能重新指向另一个数据), 底层 const 表示该指针指向的数据不能被改变.(顶层 const 可以理解成不同的类型)
底层 const 写法:
- Int num = 1;
- const int * p = # // 等价于 int const * p = &num
顶层 const 写法:
- Int num = 1;
- int * const p = #
当指针作为函数参数时, 顶层 const 可以区分, 而底层 const 不可区分
下面的写法出现重复定义:
- double cube(double x)
- double cube(const double x)
下面的底层 const 可以区分
- void dribble(char* bits);
- void dribble(const char * bits);
下面的顶层 const 不可区分:
- void dribble(char* bits);
- void dribble(char * const bits);
同理, 引用的情况是可以区分的
- double cube(double& x)
- double cube(const double & x)
左值形参和右值形参
首先区分传引用和传复制传值, 如下这两个定义会出现重复定义
- double cube(double& x);
- double cube(double x);
左值形参和右值形参情况有所不同
假设有如下定义
- double cube(double&& x)
- double cube(double x)
使用 cube(x)调用的时候调用第二个, 但使用 cube(x+1)时会出现多个匹配问题(匹配问题说明函数定义是没有歧义的, 但是在寻找对应的匹配的函数是有多个符合条件的结果, 只是不知道选哪个)
二, 函数匹配问题
定义了一组重载函数后, 我们需要以合理的实参调用它们. 函数匹配是指一个过程, 在这个过程中我们把函数调用与一组重载函数中的某一个关联起来, 函数匹配也叫做函数确定. 编译器首先将调用的实参与重载集合中每一个函数的形参进行比较, 然后根据比较的结果决定到底调用哪个函数.
现在我们需要掌握的是, 当调用重载函数时有三种可能的结果:
编译器找到一个与实参最佳匹配的函数, 并生成调用该函数的代码;
找不到任何一个函数与调用的实参匹配, 此时编译器发出无匹配的错误信息;
又多于一个函数可以匹配, 但是每一个都不是明显的最佳选择. 此时也将发生错误, 称为二义性调用.
函数匹配过程分为三步
1, 确定候选函数, 候选函数具备两个特征: 一是与被调用的函数同名, 二是其声明在调用点可见.
2, 确定可行函数, 可行函数也具备两个特征: 一是形参数量与本次调用的形参数量一致, 二是每个实参的类型与对应的形参类型相同, 或者能转化成形参的类型
3, 寻找最佳匹配, 有多个可行函数的时候, 需要选择一个最佳匹配, 基本思想是实参类型与形参类型越接近, 他们匹配得越好.
含有多个参数的函数匹配, 有且只有一个函数满足下列条件, 函数匹配成功:
l 该函数每个实参匹配都不劣于其他可行函数需要的匹配
l 至少有一个实参的匹配优于其他可行函数的匹配
比如使用 f(2,3.5)匹配下面函数时会出现冲突:
- void f(int x,int y)
- void f(double x, double y)
实参类型转换
编译器将实参到形参的转换划分为几个等级
1, 精确匹配, 包含如下情况
l 实参与形参类型相同
l 实参从数组类型或函数类型转换成对应的指针类型
l 向实参添加顶层 const 或者从实参中删除顶层 const
2, 通过 const 转换实现的匹配
3, 通过类型提升实现的转换
4, 通过算术类型 (int,short 等的转换) 或指针转换(0 或字面值 nullptr 能转换成任意指针类型, 指向任意非常量的指针能转换成 void*, 指向任意对象的指针能转换成 void*)
5, 通过类类型转换实现的匹配
区别类型的提升和转换:
把 char,unsigned char,short,unsigned short 转换成 int 类型称为类型提升(promotion)
long double,double,float,unsigned long long,long long,unsigned long,long,unsigned int,int 之间的转换称为类型转换
类型等级由高到低依次为: long double,double,float, unsigned long long,long long,unsigned long,long,unsigned int,int
区分 "忽略顶层 const" 和 "const 转换"
忽略顶层 const 的例子, 他们单独都可以被 double x = 9.0;cube(x); 两条语句调用(即使 x 是非 const, 但仍旧可以调用 double cube(const double x)), 所以以下两种是同一定义:
- double cube(const double x)
- double cube(double x)
看一个指针的例子, 下面两种同样是忽略顶层 const 的例子. 他们单独都可以被 double x = 9.0;cube(x); 两条语句调用:
- double cube(double* x)
- double cube( double* const x)
如果有 double cube(const double x), 同样可以使用以下语句调用, 因为
- double x = 9.0
- cube(&x)
以上都是顶层冲突的例子, 但是 const 转换不同, 它指非 const 的对象能被转换成 const
double cube(const double * x)
能被以下的语句调用
- double x = 9.0
- cube(&x)
x 不是 const 的, 但是传给了 const, 出现了 const 转换
来源: http://www.bubuko.com/infodetail-2599805.html