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?
}
2
  • 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. Commented Sep 19, 2011 at 19:24
  • Also note that protected data (as opposed to methods) very much opens you up to violating a base class's invariants. Commented Sep 19, 2011 at 19:50

5 Answers 5

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
}
Sign up to request clarification or add additional context in comments.

2 Comments

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

Comments

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
}

Comments

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.

6 Comments

Your example does something different from the OP's one and is misleading in this context.
Not quite true. Access restrictions are per class, not per instance.
Unless he wrote what he wanted, and foo takes a pointer to another Base* object.
@Kerrek: I think he meant Derived1 : Base can't access the x member of Derived2 : Base.
@Moo: He says "from the derived object"; that is not correct.
|
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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.