无法在C#中使用相同方法的虚拟和覆盖

所以显然你不能将virtual修饰符与override修饰符一起使用。

virtual – 可以覆盖的方法

override – 一种覆盖其父类中同名方法的方法

这让我相信,如果我覆盖子类中的方法,如果该子进程有孩子,则无法再次覆盖该方法。

可以肯定地说,如果将overridevirtual放在方法声明中,您将在C#中遇到编译错误。

但是我无法理解为什么我在下面创建的代码以它的方式工作

 using System; public class DrawingObject { public virtual void Draw() { Console.WriteLine("Drawing Object"); } } public class DrawDemo { public static int Main() { DrawingObject[] dObj = new DrawingObject[3]; dObj[0] = new DrawingObject(); dObj[1] = new Line(); dObj[2] = new LittleLine(); foreach (DrawingObject drawObj in dObj) { drawObj.Draw(); } Console.Read(); return 0; } } public class Line : DrawingObject { public override void Draw() {// the method above me is in fact virtual because LittleLine overid it? Console.WriteLine("I'm a Line."); } } public class LittleLine : Line { public override void Draw() { Console.WriteLine("I'm a Little Line."); } } 

这是输出:

绘图对象

我是一条线。

我是一条小线。

因此, Line的draw方法看起来好像被LittleLine覆盖了。 这个代码实际上没有覆盖它,还是编译器正在做其他一些技巧? 或者我不理解virtualoverride的上下文?

您可以将某个方法声明为virtual一次,但您可以根据需要多次override它 – 覆盖不是最终的,并且它不限制从第一个覆盖类inheritance的类。 最终将执行的方法是覆盖虚方法的最后一个方法。 所以你的代码确实按预期运行。

关于覆盖,C#非常冗长 – 你有比C ++或Java更多的说明符。 让程序员指定确切的意图是这样的:

  • 您使用virtual指定可以由子类重写的方法。
  • 您使用override来指定您覆盖一个您知道是虚拟的方法(如果不是,编译器将报告错误)。
  • 您使用sealed防止进一步覆盖。
  • 而你使用new来隐藏而不是覆盖。

这可能令人困惑,有时令人讨厌,但它可以确保您真正了解自己在做什么,并使您的意图自我记录。

所以显然你不能将虚拟修饰符与覆盖修饰符一起使用。

确实。 该方法保持虚拟,除非您使用声明为已sealed的方法覆盖它。 (当你覆盖某些东西时,你只能对方法使用sealed修改。)从C#4规范的第10.6.5节:

当实例方法声明包含sealed修饰符时,该方法被称为密封方法。 如果实例方法声明包含sealed修饰符,则它还必须包含override修饰符。 使用sealed修饰符可防止派生类进一步覆盖该方法。

我想你只是误解了virtual运作方式。 它不仅限于一个级别的inheritance,如下所述,例如 :

对于在类中声明或inheritance的每个虚方法,存在关于该类的方法的最派生实现。 关于类R的虚拟方法M的最派生实现确定如下:
•如果R包含M的引入虚拟声明,那么这是M的最派生实现。
•否则,如果R包含M的覆盖,那么这是M的最派生实现。
•否则,关于R的M的最派生实现与关于R的直接基类的M的最派生实现相同。

这种行为是对的。 如果您不希望inheritance的类覆盖您的虚方法,您可以将其标记为“密封”,如下所示:

 public class Line : DrawingObject { public sealed override void Draw() { Console.WriteLine("I'm a Line."); } } 

之后,LittleLine类将无法覆盖Draw方法。

virtual表示通过虚方法表调度方法。 如果方法是虚拟的,则派生类对该方法的任何引用都必须通过vtable。 你不能仅仅因为派生类重写它而非虚拟化它 – 如果将LittleLineDrawingObject会发生什么? 你仍然需要找到正确的实现,这不是DrawingObject

看起来它按预期工作。

dObj [0] = new DrawingObject();
dObj [1] = new Line();
dObj [2] =新的LittleLine();

你正在调用Draw()并在循环中

inheritance人输出绘图对象我是一条线。 我是一条小线

dObj [0] .Draw() – >“绘图对象”dObj [1] .Draw() – >“我是一条线。” dObj [2] .Draw() – >“我是一条小线”

所以Line中的draw方法看起来好像是LittleLine的Overrriden

是的,这不是你所期望的吗? 该方法在基类中标记为Virtual,您已覆盖它。 如果你想“添加它”,你需要使用其他一些模式。 也许装饰师。