为什么子类不能使用基类保护构造函数创建新对象?

时间:2011-06-03 04:57:43

标签: c# inheritance constructor protected

我正在将一些Java代码移植到C#,我遇到了这个用于复制对象的习惯用法:

class Base
{
    int x;
    public Base(int x) { this.x = x; }
    protected Base(Base other) { x = other.x; }
}

class Derived : Base
{
    Base foo;
    public Derived(Derived other)
        : base(other)
    {
        foo = new Base(other.foo); // Error CS1540
    }
}

错误CS1540:

  

无法通过“Base”类型的限定符访问受保护的成员“Base.Base(Base)”;限定符必须是'Derived'类型(或从中派生出来)

我理解此错误的目的:它阻止访问兄弟类型的受保护成员。但Base.Base(Base)显然不会在兄弟类型上调用!这根本没有包含在规范中,或者我错过了为什么这不安全的原因?

编辑:Gah,成语是new Base(other.foo)而不是new Base(other)

4 个答案:

答案 0 :(得分:4)

语言规范的第3.5.2节和第3.5.3节说明了这一点,为方便起见,我将发布3.5.2(它更短!)并让你自己找到3.5.3。

  

直观地说,当一个类型或   访问成员M,如下   评估步骤以确保   允许访问:

     
      
  • 首先,如果在一个类型中声明了M(而不是编译单元)   或命名空间),编译时错误   如果无法访问该类型,则会发生。
  •   
  • 然后,如果M是公开的,则允许访问。
  •   
  • 否则,如果M受内部保护,则允许访问   它发生在程序中   M被声明,或者如果它发生在   从类派生的类   M被宣布并发生   通过派生类类型   (§3.5.3)。
  •   
  • 否则,如果M受保护,则允许访问(如果发生)   在M所在的类中   声明,或者如果它发生在   从类中派生的类   M被宣布并通过   派生类类型(§3.5.3)。
  •   
  • 否则,如果M是内部的,则允许访问,如果它发生   在M所在的计划中   声明。
  •   
  • 否则,如果M是私有的,则允许访问,如果它发生   在M的类型内   声明。
  •   
  • 否则,类型或成员不可访问,并且编译时错误   发生。
  •   

基本上,对基础的受保护成员的访问必须通过派生的实例。正如您所说,兄弟姐妹不能访问彼此的受保护成员,但语言规范也禁止儿童访问基地的受保护成员,除非通过儿童提及。

答案 1 :(得分:4)

可以执行此操作,然后您可以始终轻松调用允许您从中派生的任何类的protected个成员,即使派生的也是如此不使用类。这完全颠覆了protected机制的安全性。

例如,假设我们从Base推导出Derived,如上所述。如果规则不是这样,您可以将这样的方法添加到Derived

public static void CallProtectedMethod(Base baseInstance)
{
    baseInstance.ProtectedMethod();
}

现在任何人都可以像这样调用它:

Derived.CallProtectedMethod(baseInstance);

直接接近失败:

baseInstance.ProtectedMethod();

在这种情况下,baseInstance可能确实属于Base类型,与Derived无关。为了防止这种情况并确保protected方法保持protected,除非实例确实属于Derived类型,否则通过其他实例调用这些方法是非法的。

同样适用于protected构造函数:

public static Base CreateProtectedBase()
{
    return new Base();
}

现在任何人都可以像这样调用它:

var baseInstance = Derived.CreateProtectedBase();

直接接近失败:

var baseInstance = new Base();

答案 2 :(得分:3)

无法访问,您可以查看此帖子了解详情:Many Questions: Protected Constructors

答案 3 :(得分:1)

如果在派生中创建新的base对象,则无法通过该对象访问受保护的成员。 试试这段代码

class Base
{
     protected int x;
}
class Derived : Base
{
    Base foo;
    void testMethod()
    {
        base.x = 5;
        foo.X = 5;// this throws an error 
    }
}

更改构造函数的访问说明符以使其工作或代替创建基类对象(Base)使用base.X