我了解到我们可以在 C++ 中为我们的类提供转换运算符。所以我预计对于以下程序,
c=1;
会使用转换运算符 int()
。但令我惊讶的是;那没有发生,我们得到一个编译器错误说
error: no match for 'operator=' (operand types are 'C' and 'int')
.
所以我想知道为什么这里没有使用转换运算符
struct C {
explicit C(int);
operator int&();
};
int main() {
C c({});
c = 1; //this gives error. Why the conversion operator int&() is not used here?
}
请注意,我知道只要从构造函数中删除
explicit
关键字就可以解决错误。但我的问题是为什么不使用转换运算符。
我想既然我们的类有一个转换运算符,那么类对象可以转换为一个
int
,这样它就可以被赋值了。
我想既然我们的类有一个转换运算符,那么可以将类对象转换为int,这样就可以赋值了。
因为内置赋值运算符的左侧操作数不考虑用户定义的转换。这可以从Operators in expression's documentation看到:
对于内置赋值运算符,左操作数的转换限制如下:
- 没有引入临时变量来保存左操作数,并且
- 没有用户定义的转换应用于左操作数以实现与内置候选的最左边参数的类型匹配。
(强调我的)
这意味着程序是病态的.
正式的解释参考这个答案。我将尝试提供一种直觉,说明为什么这不能按您预期的方式工作。 在您的问题中,您尝试计算出以下表达式
c = 1;
其中
c
是class C
的一个实例。我们可以用两种方法来解决这个问题。
int
int
.所以如果我们使用提到的表达式,上面应该就足够了。
然而,有人可能想写这样的东西。
int i = c; // again, c is instance of C
我们也(如果我们尝试思考语言设计者的想法)需要解决这个问题。因此设计者为此决定制作一个转换运算符,专门针对这种情况。
总结
A
生成 B
,我们定义一个 A
的构造函数,它接受 B
B
得到 A
(并且我们不能或不想定义接受 B
的 A
的构造函数),我们创建一个转换运算符来转换 A
到B
如我们所愿。我认为当前投票的答案是错误的。
使用
explicit
关键字的核心理念是防止隐式使用。
struct C1 {
explicit C1(int X) {cout<<"explicit"<<X<<endl;};
};
struct C2 {
C2(int X) {cout<<"implicit"<<X<<endl;};
};
int CONVERT() {
// C1 c11(1);
// c11 = 2; // this must give error. we are implicitly trying to use the explicit convertor
C1 c12(3);
c12 = (C1) 4; // this gives no error. we are explicitly trying to use the explicit convertor
C2 c21(5);
c21 = 6; // this should give no error. it is ok to use implicitly
C2 c22(7);
c22 = (C2) 8; // this too should give no error. it is ok to use explicitly
return 0;
}
当我们调用
CONVERT()
时,我们将得到这个输出:
explicit3
explicit4
implicit5
implicit6
implicit7
implicit8