
文章插图
作者 | 樱雨楼
责编 | 屠敏
出品 | CSDN(ID:CSDNnews)
在上篇中,我们讨论了C++中与隐式类型转换相关的一些话题,而函数重载是与隐式类型转换相关的又一大重要话题,本篇将要讨论的内容即为隐式类型转换与函数重载之间的相关话题 。
1.隐式类型转换与重载确定
C++中,如果同时定义了多个函数名称相同,但函数签名不同的函数,则此行为称为函数重载 。调用重载函数时,编译器将根据调用的参数数量与类型确定被调用的是哪一个函数,此过程称为重载确定 。在重载确定过程中,如果编译器发现不止一个函数都是当前调用的最佳版本,则将引发二义性编译时错误 。
需要声明的是:重载确定是一个非常复杂的话题,本文没有对重载确定的所有情况进行详尽的论述,而只是提出了其中一些与隐式类型转换关联较大的,或具有代表性的话题进行论述 。
首先,引用《C++ Primer》中对于重载确定的隐式类型转换等级的说明:
为了确定最佳匹配,编译器将实参类型到形参类型的转换划分成几个等级,具体排序如下所示:根据这段内容,我们可以得到以下要点:
1. 精确匹配,包括以下情况:
2. 通过const转换实现的匹配
- 实参类型和形参类型相同
- 实参从数组类型或函数类型转换成对应的指针类型
- 向实参添加顶层const或从实参中删除顶层const
3. 通过类型提升实现的匹配
4. 通过算术类型转换或指针转换实现的匹配
5. 通过类类型转换实现的匹配
- 数组向指针,以及函数向函数指针的隐式类型转换并不被C++视为隐式类型转换,其只是语法上的差别
- 显然,顶层const在不同变量之间不存在传递性
- 涉及底层const的类型转换被视为最接近精确匹配的隐式类型转换
- 类型提升优先于算术类型转换
- 自定义的类型转换等级最低,且各种自定义类型转换之间无先后差别
void test(int) {}void test(int, int = 0) {}int main{test(0); // 调用哪一个test?}上述代码中,我们仅通过一个int调用了test函数,此时,编译器无法确定调用的函数版本应该是void test(int)还是void test(int, int = 0),所以此调用是具有二义性的 。再来看一个根据形参类型进行重载确定的例子:
void test(int) {}void test(double) {}int main{test(0); // void test(int)test(0.); // void test(double)test('0'); // void test(int),因为char -> int比char -> double更优}上述代码中,显然,test(0)调用是void test(int)版本的精确匹配,且test(0.)调用是void test(double)版本的精确匹配 。考察test('0'),由于char -> int属于类型提升,其比char -> double更优,故编译器选择了void test(int)版本,并将char通过隐式类型转换转为int 。接下来讨论用户自定义的类型转换与重载确定之间的关系 。
首先,C++对于隐式类型转换有一条非常重要的规则:对于单次隐式类型转换,用户定义的隐式类型转换方案与算术类型转换各可出现一次,且顺序不限 。
围绕此条性质,首先可以得到的结论是:不允许出现不止一次的用户定义的隐式类型转换 。
参考以下代码:
// 定义A -> B -> C的隐式类型转换struct A {};struct B { B(const A &) {} };struct C { C(const B &) {} };int main{B b = A; // A -> BC c1 = A; // Error! 不可以连续使用两次自定义的隐式类型转换C c2 = B(A); // B -> C}上述代码中,使用A类对象对B类变量赋值是可行的,因为我们定义了A -> B的转换构造函数,但如果我们试图通过多个转换构造函数实现A -> B,然后B -> C的隐式类型转换,则会引发编译时错误 。对于同时存在算术类型转换与用户定义的类型转换的情况,重载确定将分为以下几种情况:
1. 存在精确匹配的类型转换
参考以下代码:
struct A { operator int { return 0; } operator double { return 0.; } };int main{static_cast<double>(A);}上述代码中,A类可以同时向int与double进行类型转换,由于A -> double是operator double的精确匹配,则编译器将选择此版本 。2. 存在多个可行的用户定义的类型转换,但不存在精确匹配的类型转换
参考以下代码:
struct A { operator int { return 0; } operator double { return 0.; } };int main{static_cast<long double>(A); // 二义性错误!}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 隔夜的小葱可以吃吗 沙葱隔夜能吃吗
- 全遮光的窗帘对睡眠好吗 窗帘不遮光睡觉对眼睛有害吗
- MySQL如何选择合适的索引
- 支付系统整体架构详解
- 去世一周年上坟有什么讲究 去世的人第一个清明节上坟吗
- Apache ShardingSphere开源的分布式数据库中间件
- 微信拓客的七个步骤与话术
- 创意好文案的7个套路
- 一网打尽光纤配件,弱电最全的光纤配件
- POE供电七个问题
