用户定义的转换运算符到不可访问的基数 class

User-defined conversion operator to inaccessible base class

当基数不可访问时,为什么不允许用户定义转换为基数 class(或对其的引用):protectedprivate

当存在 class D 及其 public 基础 B 时,有一个隐式规则将引用绑定到 B (B&B&&,可能是 cv 限定的)到 class D 的对象,因此用户定义的到 B& 的转换没有意义。但是当基数 class 为 protectedprivate 时,隐式规则不再适用。那么为什么不允许使用用户定义的转换为 B&(或 const B&B&& 等)?

这是允许的,标准中没有任何内容禁止这样做。但它只是声明永远不会使用这样的转换运算符。 [class.conv.fct]/1:

A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void.

重载解决方案将始终优先于基础 class 构造函数而不是转换运算符,并且永远不会调用转换运算符,因此对于隐式转换来说是不必要的。访问检查总是在重载解析之后完成,因此从不考虑转换运算符。

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 之外访问它,并且您的代码无法编译。

据我所知,这就是重载解析的工作原理。