c#中的虚拟关键字

我对java有所了解,过去几天一直在学习c#。 现在我遇到了“虚拟”关键字,正如此链接所建议的那样,用于允许在子类中覆盖相应的方法,属性等。 现在我认为即使不使用“virtual”关键字也可以覆盖方法。 那为什么有必要呢?

如果您真的想要override子类中的方法,则需要virtual关键字。 否则,基本实现将被新实现隐藏,就像您使用new关键字声明它一样。

通过“覆盖”它们而不将基本方法声明为virtual隐藏方法会使您没有多态性,这意味着:如果您将专用版本“转换”为“基本”版本并调用方法,则始终使用基类实现而不是被覆盖的版本 – 这不是你所期望的。

例:

 class A { public void Show() { Console.WriteLine("A"); } } class B : A { public void Show() { Console.WriteLine("B"); } } A a = new A(); B b = new B(); a.Show(); // "A" b.Show(); // "B" A a1 = b; a1.Show(); // "A"!!! 

virtual是一种定义方法具有默认实现的方法,但该实现可以在子类中重写。 除了使用虚拟之外,您不能在不使用new关键字的情况下直接覆盖方法(这通常是不好的做法)。

实现virtual一个很好的例子是ToString()方法。 C#中的每个对象都保证能够调用ToString()因为每个对象都从基类System.Object类inheritance,该类包含一个虚拟方法ToString() 。 然而,派生类可以覆盖它,并提供它们自己的实现,这对对象的用户可能更有用。

更新:我最近写了一篇博文,深入探讨了这个主题。 看看这里 。

现在我认为即使不使用“virtual”关键字也可以覆盖方法。

不,你不能。 与Java相反,在C#中,成员默认密封的,除非用virtual关键字标记它们,否则不能覆盖它们。

看看这个例子:

  void Main() { var o1 = new S(); Console.WriteLine(((B)o1).m1()); } public class B { public virtual string m1() { return "m1"; } } public class S : B { override public string m1() { return "overridden m1"; } } 

在此示例中,子类S被实例化并分配给对象变量o1 。 在Console.WriteLine语句的参数中,它被强制转换为基类B ,然后调用方法m1 。 因为我们在基类B使用了virtual ,并在子类S override ,所以我们得到了

被覆盖的m1

作为输出。 如果你在Bm1的方法声明中删除virtual并在子类S override ,那么你就得到了

M1

作为输出,这意味着强制转换还具有使用基类B的方法m1的原始声明的效果。

注意如果您在子类S使用new关键字,例如

  new public string m1() { return "overridden m1"; } 

假设基类B中的virtual关键字不存在,则表示您正在获取输出

M1

同样。 如果不将其强制转换为B ,则使用新方法。 这称为阴影 (或隐藏 )方法(基类的原始方法)。

摘要:

  • 要覆盖一个方法,该方法在转换为基类时也应该有效,请在基类中使用virtual关键字并在子类中override

  • 如果您打算覆盖仅在子类中处于活动状态的方法,请在子类方法声明中使用new关键字。 正如你所看到的那样它也可以没有它,但如果它存在则更好,所以每个人都知道这是该方法的新版本。