回顾: 在这篇文章中,具体的讲述了,C++函数重载的实现,是因为编译器底层使用了命名倾轧的技术,来使得相同作用域下,同名函数,依靠参数列表的不同,来进行特化区分.
也就是 c++函数名linux 下编译器命名规则为: 命名空间+函数名长度+函数名+参数类型
现在 ,我们知道了,重载的实现机制 但是仅仅依靠参数列表的不同,就能够完美的实现精准的调用吗?
你在使用的过程中难道就没有遇见过函数二义性调用吗?
如果没有请思考下列代码
#include<iostream>
#include<string>
class A
{
public:
void print(int a,int b)
{
std::cout<<" i i"<<std::endl;
}
void print(double a,int b)
{
std::cout<<"d d"<<std::endl;
}
};
int main()
{
A *a=new A();
a->print(3.1415926,6);
a->print(3.1415926,6.12);
return 0;
}
当我们调用一个已经重载过得函数时,会发生以下几件事
第一步: 确定候选函数集
确定候选集: 在重载函数集中,根据作用域和函数名,来选择同名同域的重载函数
候选函数集特点:
| |
---|
1. 该集合中的函数的声明,在该调用点可见 | 也就是,和背调函数在同一作用域下 | 2. 该集合中的函数,与被调函数同名 | 也就是,重载函数的函数名都一致 |
#include<iostream>
#include<string>
class A
{
public:
void print(int a,int b)
void print(double a,int b)
void print(string a,string b,string c)
void print(bool a,char b,float c,linklist *d,node *e)
void A(int a,int b)
void A(double a,int b)
void A(string a,string b,string c)
void A(bool a,char b,float c,linklist *d,node *e)
void B(int a,int b)
void B(double a,int b)
void B(string a,string b,string c)
void B(bool a,char b,float c,linklist *d,node *e)
};
上述代码中 重载函数集为{{A},{B},{pring}} A的候选集为:{A}={Aii,Adi,Ass,Abcfld}
第二步:选出可行函数集
在确定了候选函数集之后,根据背调函数的参数列表,选择出对应的可行函数集
参数列表信息=参数个数+参数类型
可行函数集特征
| |
---|
1. 每个实参的类型要与对应的形参类型相同,或者是能够转换成形参的类型 | c++支持隐式类型转换! | 2. 参数个数与背调函数个数匹配 | 参数类型可以隐式转换,但是参数个数相同是最低标准 |
对上述代码寻找 A(3.1415,6.12222)的可行函数集合
通过参数个数确定集合
void A(int a,int b)
void A(double a,int b)
但是究竟该选哪个呢? 注释: 如果没有找到可行函数集,则编译器将报告无法匹配函数的错误
第三步:寻找最佳匹配
第三步是,从可行函数集合中选出与本次调用最匹配的函数(注意,并不一定是完全一致的函数)
- 编译器将依次检查可行函数集中的每一个函数
- 依次检查每一个函数的形参,与被调函数的实参
- 寻找到最匹配的那个可行函数
- 匹配成功条件
- 该可行函数每个实参的匹配都不劣于其他可行函数需要的匹配
- 该可行函数至少有一个实参的匹配 优于其他可行函数提供的匹配
- 有且只有一个可行函数满足上述两个原则
注意: 有且只有一个可行函数满足,如果有多个可行函数同时满足,就会造成函数调用的二义性
大致总结
最佳匹配细节
明天考试,我先下去复习一下,施工未完成
|