无法在C#中使用相同方法的虚拟和覆盖
所以显然你不能将virtual
修饰符与override
修饰符一起使用。
virtual
– 可以覆盖的方法
override
– 一种覆盖其父类中同名方法的方法
这让我相信,如果我覆盖子类中的方法,如果该子进程有孩子,则无法再次覆盖该方法。
可以肯定地说,如果将override
和virtual
放在方法声明中,您将在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
覆盖了。 这个代码实际上没有覆盖它,还是编译器正在做其他一些技巧? 或者我不理解virtual
和override
的上下文?
您可以将某个方法声明为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。 你不能仅仅因为派生类重写它而非虚拟化它 – 如果将LittleLine
为DrawingObject
会发生什么? 你仍然需要找到正确的实现,这不是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,您已覆盖它。 如果你想“添加它”,你需要使用其他一些模式。 也许装饰师。