C++重载决议:基类指针转void*更优规则的触发场景示例
规则触发场景说明
A*到void*的转换优于B*到void*这条规则的核心作用,是在两个同等级隐式转换序列都需要最终转换为void*时,基于指针所属类型的继承关系给出优先级判断。纯标准转换场景下很难触发这条规则——因为当形参直接是void*时,编译器会直接选择最短转换路径(派生类指针直接转void*),不会生成“派生类指针→基类指针→void*”的冗余路径,自然不会出现两个待比较的void*转换序列。
这条规则最典型的触发场景是用户定义转换序列的标准转换段比较:当类同时定义了到基类指针、派生类指针的转换运算符,且调用目标形参为void*时,两条转换路径都属于可行序列,此时就需要用这条规则判定优先级。
可复现的代码示例
#include <iostream> struct A {}; struct B : A {}; struct C { operator A*() { std::cout << "调用C::operator A*()\n"; return nullptr; } operator B*() { std::cout << "调用C::operator B*()\n"; return nullptr; } }; void f(void*) { std::cout << "调用f(void*)\n"; } int main() { C c; f(c); }
规则匹配逻辑说明
调用f(c)时,编译器会生成两个可行的隐式转换序列:
- 序列1:对
c调用operator A*()得到A*类型临时值,再通过标准指针转换A*→void*匹配f的形参 - 序列2:对
c调用operator B*()得到B*类型临时值,再通过标准指针转换B*→void*匹配f的形参
两个序列同属用户定义转换等级,用户定义转换步骤本身没有优先级差异,因此需要比较用户定义转换之后的标准转换段优劣。此时恰好匹配规则的适用条件:A是B的基类,A*→void*的转换优先级高于B*→void*,因此序列1更优,编译器会选择调用operator A*()完成转换,不会产生二义性错误。
程序运行输出为:
调用C::operator A*() 调用f(void*)
如果删除这条规则,上述代码会因为两个转换序列优先级相同直接报编译期二义性错误。
补充:基类层级相关的隐式转换序列排名规则
若Mid直接或间接派生自Base,且Derived直接或间接派生自Mid:
- Derived到Mid的转换优于Derived到Base的转换
- Derived到Mid&或Mid&&的转换优于Derived到Base&或Base&&的转换
- Base::*到Mid::*的转换优于Base::*到Derived::*的转换
- Derived到Mid的转换优于Derived到Base的转换
- Mid到Base的转换优于Derived到Base的转换
- Mid到Base&或Base&&的转换优于Derived到Base&或Base&&的转换
- Mid::*到Derived::*的转换优于Base::*到Derived::*的转换
- Mid到Base的转换优于Derived到Base的转换
内容的提问来源于stack exchange,提问作者mada
相关产品推荐
相关产品推荐

