Why can a derived class not access a protected mem

2019-01-28 02:47发布

问题:

This is the code:

class TestA
{
protected:
    int test=12;

public:
    TestA() {
        cout << "test a: " << test << endl;
    }
    ~TestA() {
    }
};

class TestB : public TestA
{   
public:
    TestB(TestA *testA) {
        cout << "test b: " << testA->test;
    }
    ~TestB() {
    }
};

int main ()
{
    TestA *pTestA=new TestA();
    TestB *pTestB=new TestB(pTestA);
}

I'm trying to access of a protected member using a pointer pointing to a TestA type object (thus, an instance of TestA). TestB is also derived from TestA

Why I can't access to it? Is it accessible only "within" the class where I need it? Not outside using pointer/direct declarations?

回答1:

When public inherite from the base class, its protected members become the derived class' protect members, which could be accessed in derived class' member functions. But they could only be accessed through the derived class itself (and its derived classes), can't be accessed through the base class. So you can't access member test via pointer of TestA, but it'll be fine to access it via pointer of TestB.

The standard gives some illustrative samples for this. $11.4/1 Protected member access [class.protected]:

(Only keep a part of the example code)

An additional access check beyond those described earlier in Clause [class.access] is applied when a non-static data member or non-static member function is a protected member of its naming class ([class.access.base])114 As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C. If the access is to form a pointer to member ([expr.unary.op]), the nested-name-specifier shall denote C or a class derived from C. All other accesses involve a (possibly implicit) object expression ([expr.ref]). In this case, the class of the object expression shall be C or a class derived from C. [ Example:

class B {
protected:
  int i;
};

class D1 : public B {
};

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

void D2::mem(B* pb, D1* p1) {
  pb->i = 1;                    // ill-formed
  p1->i = 2;                    // ill-formed
  i = 3;                        // OK (access through this)
  B::i = 4;                     // OK (access through this, qualification ignored)
}

— end example ]

I'm not sure about your design's intent, making TestB friend of TestA would be a straightforward solution.



回答2:

Concept of accessibility of class members by WORLD is applicable here. WORLD can access only public members of class irrespective of how they are created/derived.

Consider the example below:

class A
{
    public:
        int public_i;
    protected:
        int protected_i;
    private:
        int private_i;

    public:
        A()
        {
            public_i = 10;
            protected_i = 20;
            private_i = 30;
        }
};

class C : protected A
{
    public:
        void Access(void)
        {
            cout << public_i << endl;
            cout << protected_i << endl;
            //cout << private_i << endl; // <- Not Allowed b'coz its private here
        }
};
class D : private A
{
    public:
        void Access(void)
        {
            cout << public_i << endl;
            cout << protected_i << endl;
            //cout << private_i << endl; // <- Not Allowed b'coz its private here
        }
};
class B : public A
{
    public:
        void Access(D *pd)
        {
            cout << public_i << endl;
            cout << protected_i << endl;
            //cout << private_i << endl; // <- Not Allowed b'coz its private here

            //pd is WORLD here
            //cout << pd->public_i << endl;    // <- Not Allowed b'coz its private here since private inheritance of A by D
            //cout << pd->protected_i << endl; // <- Not Allowed b'coz its protected here
            //cout << pd->private_i << endl; // <- Not Allowed b'coz its private here
        }
};


int main ()
{
    A objA;
    cout << objA.public_i << endl;
    //cout << objA.protected_i << endl; // <- Not Allowed b'coz its protected here
    //cout << objA.private_i << endl;   // <- Not Allowed b'coz its private here

    B objB;
    cout << objB.public_i << endl;
    //cout << objB.protected_i << endl; // <- Not Allowed b'coz its protected here
    //cout << objB.private_i << endl;   // <- Not Allowed b'coz its private here

    C objC;
    //cout << objC.public_i << endl;    // <- Not Allowed b'coz its protected here
    //cout << objC.protected_i << endl; // <- Not Allowed b'coz its protected here
    //cout << objC.private_i << endl;   // <- Not Allowed b'coz its private here

    D objD;
    //cout << objD.public_i << endl;    // <- Not Allowed b'coz its private here
    //cout << objD.protected_i << endl; // <- Not Allowed b'coz its protected here
    //cout << objD.private_i << endl;   // <- Not Allowed b'coz its private here

    //Outside class its all WORLD and WORLD can access only public members.
    //Objects and Pointers are WORLD.

    //Same thing is applicable when class members are accessed via pointers.
    B *pobjB;       //pobjB is WORLD
    cout << pobjB->public_i << endl;
    //cout << pobjB->protected_i << endl; // <- Not Allowed b'coz its protected here
    //cout << pobjB->private_i << endl;   // <- Not Allowed b'coz its private here

    objB.Access(&objD);
    objC.Access();
    objD.Access();

    return 0;
}