accessing a protected member of a base class in another subclass

Kaiserludi picture Kaiserludi · Jul 24, 2012 · Viewed 25.4k times · Source

Why does this compile:

class FooBase
{
protected:
    void fooBase(void);
};

class Foo : public FooBase
{
public:
    void foo(Foo& fooBar)
    {
        fooBar.fooBase();
    }
};

but this does not?

class FooBase
{
protected:
    void fooBase(void);
};

class Foo : public FooBase
{
public:
    void foo(FooBase& fooBar)
    {
        fooBar.fooBase();
    }
};

On the one hand C++ grants access to private/protected members for all instances of that class, but on the other hand it does not grant access to protected members of a base class for all instances of a subclass. This looks rather inconsistent to me.

I have tested compiling with VC++ and with ideone.com and both compile the first but not the second code snippet.

Answer

Rob Kennedy picture Rob Kennedy · Jul 24, 2012

When foo receives a FooBase reference, the compiler doesn't know whether the argument is a descendant of Foo, so it has to assume it's not. Foo has access to inherited protected members of other Foo objects, not all other sibling classes.

Consider this code:

class FooSibling: public FooBase { };

FooSibling sib;
Foo f;
f.foo(sib); // calls sib.fooBase()!?

If Foo::foo can call protected members of arbitrary FooBase descendants, then it can call the protected method of FooSibling, which has no direct relationship to Foo. That's not how protected access is supposed to work.

If Foo needs access to protected members of all FooBase objects, not just those that are also known to be Foo descendants, then Foo needs to be a friend of FooBase:

class FooBase
{
protected:
  void fooBase(void);
  friend class Foo;
};