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

Stu*_*ons 5 c++ language-design

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

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

Rak*_*111 4

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

转换函数永远不会用于将(可能是 cv 限定的)对象转换为(可能是 cv 限定的)相同对象类型(或对其的引用),转换为该类型的(可能是 cv 限定的)基类(或对它的引用),或(可能是简历限定的)无效。

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

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)
}
Run Code Online (Sandbox Code Playgroud)

对于 (1),复制构造函数B(const B&)比使用转换运算符 ( ) 进行转换更好DB因此[over.match.ctor]/1将选择构造函数。但直到现在才进行访问检查,并且因为B的复制构造函数是protected,所以它无法编译。

对于(2)几乎完全相同的事情。B& operator=(const B&)由重载决策选择,因为它比调用 的用户定义的转换运算符更匹配D。但现在的B赋值运算符也是protected,因此您无法在 之外访问它D,并且您的代码无法编译。

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