17

I don't understand the following, when Derived inherits from Base, it gets access to its protected members which can be accessed through Derived functions. But if, Base class tries to access its own members from Derived class (which itself allows access to Base), it doesn't get access, why?

class Base {
protected:
    int x;
};

class Derived : Base {
public:
    void foo(Base* b);
};


void Derived::foo(Base* b) {
    b->x = 2;       // cannot access protected member,
                    // though Derived inherits from Base, why?
}
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
parc84
  • 257
  • 1
  • 2
  • 5
  • In your example, `Derived` isn't accessing it's own members derived from `Base`. It's accessing some other objects member's derived from `Base`. – Mooing Duck Sep 19 '11 at 19:24
  • Also note that protected data (as opposed to methods) very much opens you up to violating a base class's invariants. – Mark B Sep 19 '11 at 19:50

5 Answers5

15

A common misunderstanding.

Inside Derived::foo(), you can access protected base members of objects of class Derived. However, *b is not of type Derived. Rather, it is of type Base, and so it does not have anything to do with your class.

It's a different matter if you take a Derived* as an argument -- then you will indeed have access to protected base members.


Let's spell it out:

struct Derived;

struct Base
{
  int f(Derived *);
protected:
  int x;
private:
  int y;
};

struct Derived : public Base
{
  int g(Base *);
  int h(Derived *);
};

int Derived::g(Base * b)
{
   return b->x; // error, protected member of unrelated class
   return b->y; // error, private member of different class
}

int Derived::h(Derived * d)
{
  return d->x;  // OK, protected base member accessible in derived class
  return d->y;  // error, private member of different class
}

int Base::f(Derived * d)
{
  return d->x;  // OK, d converts to Base*
  return d->y;  // OK, ditto
}
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Let's see. If there were no inheritance, then "protected" would be the same as "private". So "b->x" is private, and `Derived::g()` doesn't have access. Now, with inheritance, "protected" means that the `Base` *subobject* is accessible inside `Derived`. However, `b->x` does not refer to the subobject, because `b` is a pointer to `Base`, not to `Derived`. The situation changes in `Derived::h()`, because `d->x` does refer to the `x` in the subobject, and so it is accessible. – Kerrek SB Sep 19 '11 at 20:09
  • That helps me understand now, when I think about it, i think about the same reason why `b->x` couldn't be accessed via main() or globally if it were protected. – parc84 Sep 19 '11 at 20:18
6

You ran smack dab into a special rule in the standard:

11.5 Protected member access
When a friend or a member function of a derived class references a protected nonstatic member function or protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11. Except when forming a pointer to member, *the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class).

One reason for this addition access check is with regard to the behaviors of those base class protected members. Since the members are protected, a different derived class can add semantics to or even make wholesale changes in the meaning of those derived members. (This is one of the reasons why protected data is rather dangerous.) Because your class is oblivious to these additions / modifications to the base class semantics made in other derived classes, the best thing to do is to preclude access to base class members when the access would be through the base class.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
1

To provide concrete example of what others are saying:

class Base {
protected:
  int x;
};

class Derived : Base {
public:
  void foo(Derived*, Base*);
};

int main() {
  Base fiddle;
  Derived fast, furious;
  fast.foo(&furious, &fiddle);
}

void Derived::foo(Derived *d, Base* b) {
  x = 1;       // Legal, updates fast.x
  this->x = 2; // Legal, updates fast.x
  d->x = 3;    // Legal, updates furious.x
  b->x = 4;    // Error, would have updated fiddle.x
}
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
0

You have the right idea, but you're not using the protected member correctly.

void foo(Base* b) should instead be void foo();

and its implementation would be:

void Derived::foo() { return this-> x; }

Because x is a protected member, you can't access it from another object -- even if that object inherits from that class. You can only access it from the derived object itself.

tjarratt
  • 1,692
  • 9
  • 17
  • Your example does something different from the OP's one and is misleading in this context. – Nicola Musatti Sep 19 '11 at 19:25
  • Not quite true. Access restrictions are per class, not per instance. – Kerrek SB Sep 19 '11 at 19:25
  • 1
    Unless he wrote what he wanted, and foo takes a pointer to another Base* object. – Mooing Duck Sep 19 '11 at 19:25
  • @Kerrek: I think he meant `Derived1 : Base` can't access the `x` member of `Derived2 : Base`. – Mooing Duck Sep 19 '11 at 19:26
  • @Moo: He says "from the derived object"; that is not correct. – Kerrek SB Sep 19 '11 at 19:26
  • @Nicola When someone is asking about inheritance and shows me some code that has a "subclass" taking the base class as a parameter, I'm going to assume they don't understand inheritance, or protected members. Given that, I think my example is actually correct in demonstrating how and when you can access a protected member from a subclass. – tjarratt Sep 27 '11 at 16:52
0

What you've essentially done is created an instance of base that has a different relation to derived than the internal instance of base inside of derived. Setting a variable to protected gives the inherited class access to it's own internal instance of base. However, creating an object of type base in the class is something different, and therefore, does not allow access.

MGZero
  • 5,812
  • 5
  • 29
  • 46