为什么具有受保护修饰符的函数可以被覆盖并且可以在每个位置访问?

Jac*_*ack 8 c# oop d access-modifiers

我是D语言新手的C#程序员.我在D编程语言中有点与OOP混淆.

假设我有以下课程:

public class A {
   protected void foo() {
      writefln("A.foo() called.");
   }
};

public class B : A {
   public override void foo() {
      writefln("B.foo() called.");
   }
};
Run Code Online (Sandbox Code Playgroud)

protected修改意味着我可以访问该.foo()方法只是在继承的类,所以为什么这个d程序正常编译?

这相当于C#.NET:

using System;

public class A {
   protected virtual void foo() {
      Console.WriteLine("a.foo() called.");
   }
};

public class B : A {
   public override void foo() {
      Console.WriteLine("b.foo() called.");
   }
};

public class MainClass  {
   public static void Main(string[] args) {
      A a = new A();
      B b = new B();    
      a.foo();
      b.foo();
   }
};
Run Code Online (Sandbox Code Playgroud)

它不编译并给出以下错误消息(如我所料):

test.cs(10,30):错误CS0507:B.foo()': cannot change access modifiers when overriding受保护的'继承成员`A.foo()'

有人可以解释这个D行为吗?提前致谢.

Pup*_*ppy 18

防止覆盖没有任何意义.派生类可以实现允许访问的简单转发功能.考虑:

public class A {
    protected void foo() {
        writefln("A.foo() called.");
    }
};

public class B : A {
   protected override void foo() { // OK
       writefln("B.foo() called.");
   }
   public void call_foo() {
       foo(); // But I allowed public access anyway!
   }
};
Run Code Online (Sandbox Code Playgroud)

因此,即使我没有重新定义访问级别foo,我仍然允许公共访问它,你无能为力.允许重新定义只是更简单.

  • @Jack:那是因为你在原来的例子中直接调用了'A.foo()`.看看[这个](http://ideone.com/g6LXy),它似乎工作正常. (2认同)

Age*_*t_L 8

因为对于"为什么可能?"这个问题有一些很好的答案.我认为C#值得解释为什么它不可能:它是关于语言设计的"哲学",可以归结为"is-a"vs"has-a"的思想冲突.

C++是关于"有一个"的想法,其中一些被传递给D和Java.B 方法foo,这对编译器和程序员来说都是最重要的 - 而不是B是什么.在C++中,甚至可以将方法重新声明为私有(或将类继承为私有),这意味着A的成员不会被B公开.

C#是关于"is-a"概念的核心.因此,因为B实际上 A,所以B 的所有内容都必须像A中一样.编译器和程序员都不必担心更改,因为不可能进行任何更改.B总是A的完美替代品.

"is-a"哲学禁止C#程序公开以前受保护的成员,尽管通过公共包装器完成它是微不足道的.这没什么意义,这只是一个小小的不便 - 但这对于保持语言哲学的一致性是一个大问题.


Jon*_*vis 7

D的行为符合Java的行为.派生类可以为其功能提供一个访问级别,该访问级别比基类中的函数更少限制,但不是限制性更强的一个.因此,一个protected函数可以被重写为protected或者public,但是它不能被覆盖private,并且public函数只能被覆盖为public.

我不知道为什么C#会限制protected你不能用public函数覆盖它.作为一个用C++,D和Java编写了大量编程但在C#编程很少的人,C#在这里的选择对我来说毫无意义.C++,D和Java都允许它.