为什么父母可以访问子类的受保护成员的实例,如果兄弟姐妹不能?

时间:2015-05-01 13:50:59

标签: c# inheritance

正如this questionthese articles中所述,不允许以下内容:

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

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

因为如果是的话,你有这个:

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

然后:

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

这是非法的,因为即使B访问X表示它知道C具有所需的签名,仍然不允许实际访问会员。

到目前为止,这么好。但鉴于上述情况,我感到困惑的是为什么我能做到这一点:

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

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

因此,这个:

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

definition of the protected keyword说:

  

受保护的成员可以在其类和派生类实例中访问。

但现在C上的受保护成员正在A内访问,A既不是“它的类”也不是“派生类实例”,而是类。虽然protected显然可以访问签名,但兄弟示例似乎表明单独这一点不应该足够,所以为什么{{1}}授予它访问该成员的权限?

2 个答案:

答案 0 :(得分:5)

这由the specification定义:

  

在程序文本之外访问受保护的实例成员时   声明它的类,以及受保护的内部   实例成员在程序的程序文本之外访问   它被声明,访问需要通过   发生访问的派生类类型的实例。

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

在A中,可以通过A和A的实例访问x   B,因为在任何一种情况下,访问都是通过一个实例进行的   A或从A派生的类。但是,在B中,不可能   通过A的实例访问x,因为A不是从B派生的。

这一点的全部内容是,我不希望任何类C的人,虽然允许从我的班级A派生,但是在班级{{1}中访问我的“内部”状态虽然它们都分享了它们是类B的衍生物的事实。

答案 1 :(得分:4)

作为C的作者,可以选择我的基类。所以我找到A,我已经阅读了它的文档,我知道它将如何以及为什么会调用我继承的protected成员(当然,我有{{1}等选项保护我的构造函数来控制哪些类(如果有的话)可以从我的sealed派生出来。这就是我真正需要考虑的事情(在反射/完全控制场景之外,但一旦反射出现在图片中,所有投注都将被取消)。

我不必担心的是其他人决定要调用这些C方法。哪个(根据您提议的修改),他们只需创建自己的类protected,就可以从B派生出来。