Search code examples
c++inheritanceprotected

Same hierarchy, different behaviour when accessing protected member of base class


I came across this code in a past exam:

#include <iostream>
class cls1
{
protected:
    int x;

public:
    cls1()
    {
        x = 13;
    }
};
class cls2 : public cls1
{
    int y;

public:
    cls2()
    {
        y = 15;
    }
    int f(cls2 ob)
    {
        return (ob.x + ob.y);
    }
};
int main()
{
    cls2 ob;
    std::cout << ob.f(ob);
    return 0;
}

This works just fine and outputs 28. The problem is, it seems to contradict with this code (found in another exam):

#include <iostream>
class B
{
protected:
    int x;

public:
    B(int i = 28)
    {
        x = i;
    }
    virtual B f(B ob)
    {
        return x + ob.x + 1;
    }
    void afisare()
    {
        std::cout << x;
    }
};
class D : public B
{
public:
    D(int i = -32)
        : B(i)
    {
    }
    B f(B ob)
    {
        return x + ob.x - 1;/// int B::x is protected within this context
    }
};
int main()
{
    B *p1 = new D, *p2 = new B, *p3 = new B(p1->f(*p2));
    p3->afisare();
    return 0;
}

It's the same type of hierarchy, but one has access to ob.x and the other one doesn't. Can someone explain to me why that is?


Solution

  • The difference is, in the 1st case the protected member is accessed through the derived class. In the 2nd case the protected member is accessed through the base class, which is not allowed.

    For protected members,

    (emphasis mine)

    A protected member of a class is only accessible

    2) to the members and friends (until C++17) of any derived class of that class, but only when the class of the object through which the protected member is accessed is that derived class or a derived class of that derived class:

    struct Base {
      protected:
        int i;
      private:
        void g(Base& b, struct Derived& d);
    };
    
    struct Derived : Base {
      void f(Base& b, Derived& d) { // member function of a derived class
        ++d.i;                      // OK: the type of d is Derived
        ++i;                        // OK: the type of the implied '*this' is Derived
    //  ++b.i;                      // error: can't access a protected member through
                                    // Base (otherwise it would be possible to change
                                    // other derived classes, like a hypothetical
                                    // Derived2, base implementation)
      }
    };