构造函数与转换运算符的调用判定规则及优先级疑问
C++构造函数与转换运算符的调用优先级问题
1. 什么决定构造函数或转换运算符会被调用?
说白了,这完全看你当前要完成的类型转换方向,以及编译器匹配转换路径的规则:
- 假设你需要把类型A的对象转成类型B,编译器会先扫两条可行路径:
- 类型B有没有能接受A的转换构造函数(也就是参数为A或A的引用的构造函数);
- 类型A有没有能直接转出成B的转换运算符(比如类A里定义的
operator B()成员函数)。
- 如果两条路径都能走通,就会触发二义性判断:要么根据C++标准的优先级规则选择其中一条,要么因为规则无法区分直接报错。
2. 为啥你的代码里构造函数优先被调用?
先看你提供的代码:
#include<iostream> using namespace std; class C1; class C2 { int x; public: operator C2() { C2 temp; cout<<"operator function called"<<endl; return temp; } }; class C1 { int x; public: C1():x(10){} C1(C2) { cout<<"constructor called"<<endl; } }; int main() { C1 obj1; C2 obj2; obj1=obj2; }
核心逻辑是obj1=obj2;这一行:obj1是C1类型,obj2是C2类型,这里需要把C2转成C1才能完成赋值。但你写的C2转换运算符是operator C2()——这是把C2转成C2的自转换,跟C1完全没关系!所以编译器要完成C2到C1的转换时,根本找不到这条路径,只能走C1中接受C2的构造函数,自然就输出constructor called了。
要是你是笔误,比如把C2的转换运算符写成operator C1(),那这时候就会出现两条等价的转换路径:
- 用
C1的构造函数:把obj2传给C1(C2)生成临时C1对象,再赋值给obj1; - 用
C2的转换运算符:把obj2直接转成C1对象,再赋值给obj1。
这时候按照C++标准,这属于等价的用户定义转换序列,编译器会判定为二义性,直接编译失败,不会优先选择某一个。
再补充几个实用的优先级规则:
- 对于隐式转换:
- 如果两条转换路径都是纯用户定义转换(比如上面的笔误场景),直接报二义性;
- 如果其中一条是「标准转换+用户定义转换」,另一条是纯用户定义转换,编译器会选步骤更少的那条。
- 要是你想明确指定走哪条路径,用显式转换即可,比如
obj1 = static_cast<C1>(obj2);或者obj1 = obj2.operator C1();,这样就能避免歧义。
内容的提问来源于stack exchange,提问作者Pritul Dave
相关产品推荐
相关产品推荐

