为什么不允许用户定义转换到基类不可用时的基类(或引用):protected
或private
?用户定义的转换运算符到不可访问的基类
当有一类D
及其public
基B
,有结合引用B
(B&
或B&&
,可能CV修饰)到类D
的对象的隐式规则,所以用户定义转换到B&
没有意义。但是,当基类为protected
或private
时,隐式规则不再适用。那么为什么不允许使用用户定义的转换为B&
(或const B&
或B&&
等)?
为什么不允许用户定义转换到基类不可用时的基类(或引用):protected
或private
?用户定义的转换运算符到不可访问的基类
当有一类D
及其public
基B
,有结合引用B
(B&
或B&&
,可能CV修饰)到类D
的对象的隐式规则,所以用户定义转换到B&
没有意义。但是,当基类为protected
或private
时,隐式规则不再适用。那么为什么不允许使用用户定义的转换为B&
(或const B&
或B&&
等)?
这是允许的,标准中没有任何内容禁止这一点。但它只是说,这样一个转换算子将永远不会被使用。 [class.conv.fct]/1
:
A转换函数从不用于转换(可能CV-合格)对象(可能CV修饰)相同的对象类型(或对它的引用),在(可能CV-合格)该类型的基类(或对其的引用),或者(可能是cv-qualified)void。
重载解析将始终优先于基类构造函数而不是转换运算符,并且转换运算符将永远不会被调用,因此对于隐式转换是不必要的。访问检查总是在超载解析后完成,所以从不考虑转换运算符。
struct B {
B() = default;
B(const B&) = default;
B& operator=(const B&) = default;
};
struct D : protected B {
operator B() { return *this; }
};
int main() {
D d;
B b = d; // (1)
b = d; // (2)
}
对于(1),拷贝构造B(const B&)
是更好的匹配然后使用转换运算符([over.match.ctor]/1
)转化D
到B
,以便构造将被选择。但是现在只是检查访问,并且由于B
的拷贝构造函数是protected
,所以它不能编译。
对于(2)几乎完全相同的东西。 B& operator=(const B&)
由重载分辨率选择,因为它比调用D
的用户定义的转换运算符更好。但是现在B
的赋值运算符也是protected
,所以你不能在D
之外访问它,并且你的代码不能编译。
这就是重载分辨率是如何工作的,据我所知这是唯一的原因。
“允许,标准中没有任何内容禁止使用”,您可以阅读“不允许”作为“未使用”。这在措词上只是不准确。 –
您能否举一个您想要做的转换的例子,但它被禁止? – dasblinkenlight
这是很不清楚你问的。请举例说明问题,[mcve]。 – Rakete1111
@dasblinkenlight它不被禁止,但从来没有被编译器考虑过,因为现在的规则。 –