为什么带有 protected 修饰符的函数可以在任何地方被覆盖和访问?

问题描述 投票:0回答:3

我是一名刚刚接触 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.");
   }
};

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();
   }
};

它无法编译并给出以下错误消息(如预期):

test.cs(10,30):错误CS0507:

B.foo()': cannot change access modifiers when overriding 
protected'继承成员`A.foo()'

有人可以解释一下这种 D 行为吗?

c# oop d access-modifiers
3个回答
22
投票

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

public class A {
    protected virtual 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!
   }
};

因此,即使我没有重新定义

foo
的访问级别,我仍然允许公众访问它并且您对此无能为力。允许重新定义就更简单了。


8
投票

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

C++ 都是关于“has-a”的思维,其中一些被传递给了 D 和 Java。 B 方法

foo
,这对于编译器和程序员来说都是最重要的——而不是B是什么。在 C++ 中,甚至可以将方法重新声明为私有(或将类继承为私有),这意味着 A 的成员不会被 B 公开。

C# 是“is-a”概念的核心。因此,因为这里 B 实际上是 A,所以 B 中的所有内容都必须与 A 中的一样。编译器和程序员都不必担心更改,因为不可能更改。 B 始终是 A 的完美替代品。 “is-a”哲学禁止 C# 程序公开以前受保护的成员,尽管通过公共包装器实现这一点很简单。这没有什么意义,而且只是一个小小的不便——但对于保持语言哲学的一致性来说却是一件大事。


7
投票
protected

函数可以重写为

protected
public
,但不能重写为
private
,并且
public
函数只能重写为
public

我不知道为什么 C# 会限制

protected

,这样你就不能用

public
函数覆盖它。作为一个经常使用 C++、D 和 Java 进行编程但很少使用 C# 的人,这里选择 C# 对我来说没有什么意义。 C++、D 和 Java 都允许。
    

© www.soinside.com 2019 - 2024. All rights reserved.