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

时间:2017-07-01 18:24:12

标签: c++ language-design

为什么不允许用户定义转换为基类不可用的基类(或引用它):protectedprivate

如果有一个班级D及其public基座B,则会有一个隐含的规则来绑定对B的引用(B&或{{ 1}},可能是cv-qualified)到类B&&的对象,因此用户定义到D的转换没有意义。但是当基类为B&protected时,隐式规则不再适用。那么为什么不允许将用户定义的转换用于private(或B&const B&等)?

1 个答案:

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

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