无法在派生类型的范围内访问另一个实例的受保护成员

4
在对问题“为什么我的对象无法访问在公共基类中定义的另一个对象的受保护成员?”的此答案中,可以看到以下内容:

只能从自己的基类实例中访问受保护的成员。

我可能没有理解正确,或者以下最小工作示例(在线演示)证明其错误。
struct Base           { void f(); protected: int prot; };
struct Derived : Base { void g(); private:   int priv; };

void Base::f()
{
    Base b;
    b.prot = prot;
    (void) b;
}

void Derived::g()
{
    {
        Derived d;
        (void) d.priv;
    }

    {
        Derived& d = *this;
        (void) d.priv;
    }

    {
        Derived d;
        (void) d.prot; // <-- access to other instance's protected member
    }

    {
        Derived& d = *this;
        (void) d.prot;
    }

    // ---

    {
        Base b;
        (void) b.prot; // error: 'int Base::prot' is protected within this context
    }

    {
        Base& b = *this;
        (void) b.prot; // error: 'int Base::prot' is protected within this context
    }
}

鉴于我遇到的这两个错误,我开始想:为什么我可以从“Derived”的范围内访问另一个“Derived”实例的受保护成员,但无论“Derived”是否从“Base”派生,都无法在相同的范围内访问另一个“Base”实例的受保护成员?简而言之:在这种情况下,“protected”比“private”更“私有”的原因是什么?
注: 请不要将此问题视为链接问题; 欢迎提出更好的标题建议。

即使您在作用域中看到对象,访问说明符的工作方式仍然相同。您使用一个Base引用,就这样。 - StoryTeller - Unslander Monica
1个回答

4

[class.access.base]中的规则是:

如果成员m在类N中命名,且...

  • m作为N的成员是受保护的,并且R出现在N的成员或友元函数中,或者出现在派生自N的类P的成员中,其中m作为P的成员是publicprivateprotected

里面有很多字母,但基本上有两个条件:

  1. R在类的成员或友元中。这处理了d.prot的例子 - 我们在Derived的成员中,同时访问Derived的受保护成员。
  2. R在派生类的成员中,并且正在访问的成员是派生类实例的成员。这处理了b.prot的例子 - 我们在派生类的成员中,但prot不是派生类的成员。

换句话说,Derived可以访问Base的受保护成员 - 但只有在访问自己子对象的受保护成员的情况下才能访问。它不能访问其他Base对象的受保护成员。当您考虑到这个其他的Base可能很容易就是SomeOtherDerived时,这是有道理的,因为那只是另一个与我们无特殊访问权限的不相关的对象。


这个答案确认了protected访问修饰符不像privatepublic那样简单! - YSC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接