【问题标题】:Derived-to-base conversion and friendship confusion派生到基础的转换和友谊混乱
【发布时间】:2016-01-10 07:48:31
【问题描述】:

来自 C++ Primer 5th edition(D 继承自 B)

如果 D 使用 public 或 protected 从 B 继承,则从 D 派生的类的成员函数和朋友可以使用派生到基的转换。这样的 如果 D 从 B 私有继承,代码可能不会使用转换。

这有什么原因吗,还是我打算从表面上看?为什么会这样似乎很明显,但在一个例子中它让我绊倒了:

#include <iostream>
using namespace std;

class Base { 
public: 
    int x = 2;
};

class Derived : protected Base { };

class DerivedAgain : public Derived {
    friend void test();
};

void test() {
    ??? a;
    Base* p = &a;
    cout << p->x;
}

int main(){
    test();
}

我想了解 test() 在派生到基础的转换中对成员 x 的可访问性。考虑函数test()a 类型??? 的三种潜在情况。

  1. ???BasexBase 的公共成员。在这种情况下没有问题。
  2. ???DerivedAgain。在这种情况下,Derived-to-Base 转换是有意义的,因为test() 具有friendDerivedAgain 的所有成员的访问权,包括从Base 间接继承的那些成员。所以使用指针访问x没有问题。
  3. ???Derived。它编译得很好。但为什么?在这一点上我很困惑。 test() 没有对 Derived 类成员的特殊访问权限,那么为什么 p-&gt;x 应该工作,因此派生到基的转换是有效的?只是因为它起作用吗?

如果我将test()的操作改为

void test() {
    Derived a;
    cout << a.x;
}

它无法编译,正如我所期望的那样 - 因为 Derived 对象继承的 x 成员被设为 protected,因此不能被用户使用。

如果我用BaseDerivedAgain 替换a 的类型,修改后的test() 可以正常编译,正如我所期望的那样。

如果第二级派生类的友元函数没有对第一级派生的特殊访问权限,为什么允许第二级派生类的友元函数使用第一级直接到基数转换,我只是感到困惑班级成员。

【问题讨论】:

    标签: c++ inheritance friend


    【解决方案1】:

    基本上,受保护的继承很奇怪。它编译的原因是,从 N4527 的 [class.access.base] 开始:

    N 的基类 BR可访问,如果
    B 的发明公共成员将是 N 的公共成员,或者
    R 出现在 N 类的成员或朋友中,B 的发明公共成员将是私人或 N 的受保护成员,或
    R 出现在派生自N 的类P 的成员或朋友中,而B 的发明公共成员将 成为P 的私人或受保护成员,或
    — 存在一个类S,这样BS 的基类,可在R 访问,SN 的基类可访问 在 R.

    这里的第三个要点是相关的。 R 出现在派生自N (Derived) 的类P (DerivedAgain) 的朋友(test) 和B (@) 的发明公共成员中987654348@) 将是P (DerivedAgain) 的受保护成员。

    我以前认为接受此代码是一个 gcc 错误 (bug 67493),但现在我认为不接受它是一个 clang 错误 - 尽管 T.C. 还指出,存在相关标准缺陷(CWG #1873)。那里的措辞更改仅适用于成员访问,而这里与我们相关的是基本访问。但也许 gcc 只是在执行标准的规则(接受是正确的),而 clang 遵循这个缺陷报告的逻辑结论(当前活跃的CWG #472)并且只是不允许它。

    再一次,受保护的继承真的很奇怪。欢迎来到精彩的 C++ 世界。

    【讨论】:

    • 我不相信,请参阅 [class.access.base]/4:“如果 [...] R 出现在成员或朋友中,则可以在 R 处访问 N 的基类 B一个派生自 N 的类 P,而一个发明的 B 的公共成员将是 P" 的私有或受保护成员。
    • @T.C.你是对的。那么 Clang 错误。受保护的继承也很奇怪。
    • CWG 1873 的解析原理可能适用于此处,这可能会使其成为标准中的缺陷。呃。
    • @T.C.那么缺陷报告的缺陷报告,因为他们只是更改了成员访问权限而不是基类访问权限?
    • @T.C.你怎么知道某件事是否被采用?例如,472 中的措辞没有出现在 N4572 中。而其他措辞似乎已被接受。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多