这是一个显示虚拟方法的小代码。
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
}
class B: A
{
public override void F() { Console.WriteLine("B.F"); }
}
class C: B
{
new public virtual void F() { Console.WriteLine("C.F"); }
}
class D: C
{
public override void F() { Console.WriteLine("D.F"); }
}
class Test
{
static void Main()
{
D d = new D();
A a = d;
B b = d;
a.F();
b.F();
}
}
此代码正在打印以下输出:
B.F
B.F
我无法理解为什么a.F()会打印B.F?
我认为它会打印DF,因为B类会覆盖A类的F(),然后使用“new”关键字将此方法隐藏在C类中,然后再次在D类中重写。所以最终DF保持不变
但它没有这样做。你能解释为什么要打印B.F?
答案 0 :(得分:5)
A a = d;
a.F();
它会发现F()
如下。
class A
class B
class C
class D
现在F()
和A
中会找到B
。因此将调用B.F()
。在class C
中,F()是不同的(因为它是新的实现,不会从A / B覆盖)。所以在第3步中,将找不到c.F()。在D类中,它会覆盖由C创建的新函数,因此也无法找到它。
由于新的关键字,结果代码如下(关于虚拟覆盖)
class A
{
public virtual void F() { Console.WriteLine("A.F"); }
}
class B: A
{
public override void F() { Console.WriteLine("B.F"); }
}
class C: B
{
public virtual void F1() { Console.WriteLine("C.F"); }
}
class D: C
{
public override void F1() { Console.WriteLine("D.F"); }
}
答案 1 :(得分:2)
与允许多态的方法覆盖不同,使用new
关键字隐藏方法只是命名问题(请注意,使用new
只会删除隐藏某些内容的警告。)< / p>
在课程C
中,当您声明:
new public virtual void F() { ... }
在这里,您要定义一个与超类F()
无关的全新方法,该方法恰好具有相同的名称。
将F
的实例分配给A
或B
类型的变量时,使用这些变量调用F()
指向超类定义的方法。
想象一下,如果你没有调用C
的方法F()
,而是调用G()
之类的方法。以下代码无法编译:
a.G();
b.G();
由于变量静态类型为A
或B
,编译器无法看到新声明的方法。在您的示例中,情况也是如此,除了超类恰好调用名为F()
的原始方法。
答案 2 :(得分:1)
现在C.F用新关键字隐藏B.F. C.F与B.F / A.F无关。当你创建C,并调用F()时,它将执行C.F.如果将C转换为A或B类型,并调用F,它将执行B.F,因为B.F和A.F已连接。
D.F被C.F.覆盖。他们是连接的。当调用C.F或D.F时,它将执行D.F.现在,当您将对象D转换为A或B并调用F()时,它将调用B.F。希望这有助于使其更清晰。
答案 3 :(得分:0)
正如其他人已经指出的那样,C中的new关键字隐藏了F的重载,因此在C或D中找不到适合的F重载。
如果您需要有关C#找到正确过载的更多详细信息,请阅读 那两个:
Jon Skeet: C# in Depth, chapter Overloading
Visual Studio 2010: Breaking changes, here: overload resolution