Topic: Access to protected inherited members


Author: sdouglass@armltd.co.uk (scott douglass)
Date: 24 Mar 1995 11:29:48 GMT
Raw View
Hello,

(11.5) has the following sentence that has been added since the ARM:

"When a protected member of a base class appears in a <qualified-id> in a
friend or a member function of a derived class, the
<nested-name-specifier> must name the derived class."

I believe that this was added to prevent users from using pointers to
members to get to protected members they are not supposed to get to.  And
I think this is a good goal.  The example changed to show that trying to
do this is now an error.

But by using the term <qualified-id> the following code has become illegal:

struct X { protected: int f(); };
struct Y : public X { int f(); };

int Y::f() { return X::f() + 1; }       // now illegal 'X::f' is a
<qualified-id>

Also previously legal was accessing protected static members using a
<qualified-id>:

struct S { protected: static int i; };
struct T : public S { int f(); };

int T::f(int i) { return i + S::i + 1; }       // now illegal 'S::i' is a
<qualified-id>

Was this indended?  These would remain legal if (11.5) were worded
something like:

(11.5) "When a pointer to a protected non-static member of a base class is
formed using &<qualified-id> in a friend or a member function of a derived
class, the <nested-name-specifier> must name the derived class."

This also would allow pointers to protected static members, which is
consistent with being able to access them directl.  The fully fleshed-out
example would now look like:

class B {
protected:
    int i;
    void mem();
static int st;
};

class D1 : public B {
};

class D2 : public B {
    friend void fr(B*,D1*,D2*);
    mem(B*,D1*);
};


void fr(B* pb, D1* p1, D2* p2)
{
    pb->i = 1;  // illegal
    p1->i = 2;  // illegal
    p2->i = 3;  // ok
    B::st = 4;  // ok
    int B::*  pmi_B = &B::i;    // illegal
    int D2::* pmi_D2 = &D2::i;  // ok
    int*      pi = &B::st;      // ok
    B::mem(pb, p1);  // ok, same as 'mem()'
}

void D2::mem(B* pb, D1* p1)
{
    pb->i = 1;  // illegal
    p1->i = 2;  // illegal
    i = 3;      // ok (access through 'this')
    B::st = 4;  // ok, same as 'st = 4'
    B::mem(pb, p1);  // ok, same as 'mem()'
}

void g(B* pb, D1* p1, D2* p2)
{
    pb->i = 1;  // illegal
    p1->i = 2;  // illegal
    p2->i = 3;  // illegal
    B::st = 4;  // illegal
    int B::*  pmi_B = &B::i;    // illegal
    int*      pi = &B::st;      // illegal
    pb->mem(pb, p1); // illegal
    p1->mem(pb, p1); // illegal
}
       --scott