Why Can't I Access A Protected Member From A Derived Class?

Why Can't I Access A Protected Member From A Derived Class?

  • Comments 9

A question I got recently was about access to protected methods from a derived class. Clearly that's what "protected" means – that you can access it from a derived class. In that case, why doesn't this work?

class Ungulate {
  protected void Eat() { /* whatever */ }
}

class Giraffe : Ungulate {
  public static void FeedThem() {
    Giraffe g1 = new Giraffe();
    Ungulate g2 = new Giraffe();
    g1.Eat(); // fine
    g2.Eat(); // compile-time error "Cannot access protected member"
  }
}

What the heck? Giraffe is derived from Ungulate, so why can't it always call the protected method?

To understand, you have to think like the compiler. The compiler can only reason from the static type information, not from the fact that we know that at runtime g2 actually will be a Giraffe. For all the compiler knows from the static type analysis, what we've actually got here is

class Ungulate {
  protected virtual void Eat() { /* whatever */ }
}

class Zebra : Ungulate {
  protected override void Eat() { /* whatever */ }
}

class Giraffe : Ungulate {
  public static void FeedThem() {
    Giraffe g1 = new Giraffe();
    Ungulate g2 = new Zebra();
    g1.Eat(); // fine
    g2.Eat(); // compile-time error "Cannot access protected member"
  }
}

We can call Ungulate.Eat legally from Giraffe, but we can't call the protected method Zebra.Eat from anything except Zebra or a subclass of Zebra. Since the compiler cannot determine from the static analysis that we are not in this illegal situation, it must flag it as being illegal.

Incidentally, C++ has the same rule.

  • The compiler surelly knows that it's in a Ungulate derived class. So, the rule could be another one.
    Nevertheless, the rule makes sense to me.
  • I think that the real problem is that the FeedThem method is in the wrong class. As soon as you put FeedThem in the right place you will not need the construction you just created.
  • But being in an ungulate-derived class is in this example not enough information to guarantee that you are in a derived class of the RUN TIME type of the callee.

    Really what you're saying is that "protected" could be redefined to mean something weaker, such as "callable from any class derived from the base class which declares the protected method".

    But that's not the kind of protection we've chosen as interesting or valuable. "Sibling" classes do _not_ get to be friendly with each other because otherwise protection is very little protection.
  • I am not sure how this figures but I tried your example on JVM out of curiosity and it worked without any errors. This is what I used -
    public class Mammal {
    protected void Eat() {
    System.out.println("In Mammal.eat()");
    }
    }
    public class Giraffe extends Mammal {
    public static void FeedThem() {
    Giraffe g1 = new Giraffe();
    Mammal g2 = new Giraffe();
    g1.Eat(); // fine
    g2.Eat(); // fine
    }
    public static void main(String[] args) {
    Giraffe.FeedThem();
    }
    }

    This might sound like a dumb question but if what you have shown is specific to C# then what is the rationale behind having such checking?
  • I've only ever written one program in Java and that was about ten years ago, so I'm a bad person to ask about Java semantics.

    However, my reading of section 6.6.2 of my 1996 copy of the JLS is that in your example, the semantics of "protected" do not apply because the two classes are in the same package.

    If you read section 6.6.7, it describes the semantics of cross-package access to protected members via subclasses as being the same as I describe above.

    Apparently in Java, "protected" means roughly what "Protected Friend" means in Visual Basic.
  • This is a follow-up to my 2005 post on the same subject which I believe sets a personal record for the

  • Well.

    While this doesn't compile:

    class Ungulate {

     protected void Eat() { /* whatever */ }

    }

    class Giraffe : Ungulate {

     public static void FeedThem() {

       Giraffe g1 = new Giraffe();

       Ungulate g2 = new Giraffe();

       g1.Eat(); // fine

       g2.Eat(); // compile-time error "Cannot access protected member"

     }

    }

    Making a subtile change (adding internal):

    class Ungulate {

     protected internal void Eat() { /* whatever */ }

    }

    class Giraffe : Ungulate {

     public static void FeedThem() {

       Giraffe g1 = new Giraffe();

       Ungulate g2 = new Giraffe();

       g1.Eat(); // fine

       g2.Eat(); // compile-time error "Cannot access protected member"

     }

    }

    Tadaa: this will compile ... and I am really happy about that ... please don't fix this bug ;)

  • That's not a bug. I'll be writing about that feature in my blog next week.

  • But the compiler's static type analysis can't detect this situation:

    class RoboGiraffe : Giraffe {

     protected override void Eat() { /* use dangerous lasers that only RoboGiraffe is trained for */ }

    }

    Now when we say g1.Eat(), we may be calling RoboGiraffe.Eat, which should only be accessible from RoboGiraffe and its subclasses, right? Shouldn't that be prohibited under the very same logic that prevents us from calling Zebra.Eat?

Page 1 of 1 (9 items)