为什么不允许用户定义转换为基类不可用的基类(或引用它):protected
或private
?
如果有一个班级D
及其public
基座B
,则会有一个隐含的规则来绑定对B
的引用(B&
或{{ 1}},可能是cv-qualified)到类B&&
的对象,因此用户定义到D
的转换没有意义。但是当基类为B&
或protected
时,隐式规则不再适用。那么为什么不允许将用户定义的转换用于private
(或B&
或const B&
等)?
答案 0 :(得分:1)
允许,标准中没有任何内容禁止此操作。但它只是声明永远不会使用这样的转换运算符。 [class.conv.fct]/1
:
转换函数永远不会用于将(可能是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
之外访问它,并且您的代码无法编译。
这就是重载解析的工作原理,据我所知这是唯一的原因。