显然,您无法将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
的背景?
答案 0 :(得分:25)
您可以将某个方法声明为virtual
一次,但您可以override
将它多次声明 - 覆盖不是最终的,并且它不会限制继承自第一次重写课程。最终将执行的方法是覆盖虚方法的最后一个方法。所以你的代码确实按预期运行。
关于覆盖,C#非常冗长 - 你有比C ++或Java更多的说明符。让程序员指定确切的意图是这样的:
virtual
指定方法可以被子类覆盖。 override
指定您覆盖一个您知道是虚拟的方法(如果不是,编译器将报告错误)。 sealed
来阻止进一步覆盖。 new
隐藏而不是覆盖。 这可能令人困惑,有时令人讨厌,但它可以确保你真正知道自己在做什么,这会让你的意图自我记录。
答案 1 :(得分:4)
显然你不能将虚拟修饰符与覆盖修饰符一起使用。
事实上。该方法保持虚拟,除非您使用也声明为sealed
的方法覆盖它。 (当你覆盖某些东西时,你可以仅对方法使用sealed
修改。)来自C#4规范的第10.6.5节:
当实例方法声明包含sealed修饰符时,该方法被称为密封方法。如果实例方法声明包含sealed修饰符,则它还必须包含override修饰符。使用sealed修饰符可以防止派生类进一步覆盖该方法。
答案 2 :(得分:2)
我认为你只是误解了virtual
是如何运作的。它不仅限于一个级别的继承,如here, for example所述:
对于在类中声明或继承的每个虚方法,都存在与该类相关的方法的最派生实现。关于类R的虚拟方法M的最衍生实现确定如下:
•如果R包含M的引入虚拟声明,那么这是M.
的派生最多的实现 •否则,如果R包含M的覆盖,则这是M.
的派生最多的实现 •否则,关于R的M的派生最多的实现与关于R的直接基类的M的最派生实现相同。
答案 3 :(得分:2)
这种行为是对的。如果您不希望继承的类覆盖您的虚方法,您可以将其标记为“密封”,如下所示:
public class Line : DrawingObject
{
public sealed override void Draw()
{
Console.WriteLine("I'm a Line.");
}
}
之后,LittleLine类将无法覆盖Draw方法。
答案 4 :(得分:1)
virtual
表示您的方法是通过虚方法表调度的。如果方法是虚拟的,则派生类上对该方法的任何引用都必须通过vtable。您不能仅因为派生类重写它而非虚拟化它 - 如果将LittleLine
强制转换为DrawingObject
会发生什么?您仍然需要找到正确的实现,这不是DrawingObject
的
答案 5 :(得分:1)
看起来它按预期工作。
dObj [0] = new DrawingObject();
dObj [1] = new Line();
dObj [2] =新的LittleLine();
你正在调用Draw()并在循环中
继承人输出绘图对象我是一条线。我是一条小线
dObj [0] .Draw() - > “绘图对象” dObj [1] .Draw() - > “我是一条线。” dObj [2] .Draw() - > “我是一条小线”
所以Line中的draw方法看起来好像是Overrriden by LittleLine
是的,这不是你所期望的吗?该方法在基类中标记为Virtual,并且您已覆盖它。如果你想“添加它”,你需要使用其他一些模式。也许装饰师。