YSC YSC - 8 days ago 4
C++ Question

Cannot access protected member of another instance from derived type's scope

In this answer to the question "Why can't my object access protected members of another object defined in common base class?", one can read:


You can only access protected members from your own base class instance.


Either I don't get it correctly or the following MCVE (live on coliru) proves it wrong:

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
}
}


In the light of the two errors I get to wonder: why can I access to another
Derived
instance's protected member from the scope of
Derived
but cannot access to another
Base
instance's protected member from the same scope regardless of the fact that
Derived
devires from
Base
? Tl; dr: what makes
protected
more "private" than
private
in this case?

Notes:


  • please don't close this question as a duplicate of the linked question;

  • better title suggestion are welcome.


Answer

The rule in [class.access.base] is:

A member m is accessible at the point R when named in class N if [...]

  • m as a member of N is protected, and R occurs in a member or friend of class N, or in a member of a class P derived from N, where m as a member of P is public, private, or protected

There's a lot of letters in there. But there are basically two conditions:

  1. R is in a member or friend of the class. This handles the d.prot example - we are in a member of Derived while accessing a protected member of Derived.
  2. R is in a member of a derived class and the member being accessed is a member of the derived class instance. This handles the b.prot example - we are in a member of a derived class, but prot is not a member of the derived class.

In other words, Derived can access Base's protected members - but only in the case that it is accessing its own subobject's protected members. It cannot access other Base object's protected members. This makes sense when you consider that this other Base could easily be SomeOtherDerived, in which case that's just another unrelated object to us that we have no special access privileges to.