Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can parents access instances of child class' protected members, if siblings can't?

Tags:

c#

inheritance

As explained in this question, and these articles, the following is not allowed:

public class A
{
    protected virtual int X {get; private set;}
}

public class B : A
{
    public int Add(A other)
    {
        return X + other.X;
    }
}

Because if it was, and you had this:

public class C : A 
{  
    protected override int X { get { return 4; } }
}

and then:

A c = new C();
B b = new B();
b.Add(c);

This is illegal because even though B's access to X means it knows that C has the desired signature it's still not allowed to actually access the member.


So far, so good. But given the above, what I'm confused about is why I can do this:

public class A
{
    protected virtual int X { get; private set; }

    public int Add(A other)
    {
        return X + other.X;
    }
}

And, therefore, this:

A c = new C();
A a = new A();
a.Add(c);

The definition of the protected keyword says:

A protected member is accessible within its class and by derived class instances.

But now the protected member on C is being accessed from within A, which is neither "its class" nor a "derived class instance", but a parent class. While A obviously has access to the signature, the sibling example seems to indicate that that alone is not supposed to be sufficent, so why is protected granting it access to the member?

like image 277
Ben Aaronson Avatar asked May 01 '15 13:05

Ben Aaronson


2 Answers

This is defined by the specification:

When a protected instance member is accessed outside the program text of the class in which it is declared, and when a protected internal instance member is accessed outside the program text of the program in which it is declared, the access is required to take place through an instance of the derived class type in which the access occurs.:

public class A
{
   protected int x;
   static void F(A a, B b)
   {
      a.x = 1;      // Ok
      b.x = 1;      // Ok
   }
}

public class B : A
{
   static void F(A a, B b) 
   {
      a.x = 1;      // Error, must access through instance of B
      b.x = 1;      // Ok
   }
}

within A, it is possible to access x through instances of both A and B, since in either case the access takes place through an instance of A or a class derived from A. However, within B, it is not possible to access x through an instance of A, since A does not derive from B.

The entire point of this being the fact that I wouldn't want anyone of class C, although allowed to derive from my class A, access my "internal" state in class B, although both of them share the fact that they are derivatives of class A.

like image 69
Yuval Itzchakov Avatar answered Sep 20 '22 14:09

Yuval Itzchakov


As the author of C, I get to choose my base class. So I've found A, I've read its documentation, I know how and why it will invoke any of my inherited protected members (and, of course, I have options such as sealed or protecting my constructors to control which classes, if any, can derive from my C). That's all I really have to think about (outside of reflection/full control scenarios, but once reflection is in the picture all bets are off).

What I don't have to worry about is someone else deciding they want to invoke those protected methods. Which (under your proposed modification), they'd be able to do by simply creating their own class, B, derived from A.

like image 42
Damien_The_Unbeliever Avatar answered Sep 20 '22 14:09

Damien_The_Unbeliever