2

这是c#代码

class A {
   public int Foo(){ return 5;}
   public virtual int Bar(){return 5;}
}
class B : A{
   public new int Foo() { return 1;}     //shadow
   public override int Bar() {return 1;} //override
}

的输出

Console.WriteLine(((A)clB).Foo()); // output 5 <<<--
Console.WriteLine(((A)clB).Bar()); // output 1

我们如何得到这个输出。任何人都可以在这里解释类转换过程。

更新:

以及这如何显示阴影和覆盖之间的区别

4

4 回答 4

6

我会假设

var clB = new B();

FooBar方法之间的区别在于,虽然Bar使用继承和多态性来决定调用什么实现,但该Foo方法隐藏了它的原始实现。

总之,一个词,A.Foo()完全B.Foo()不相关,只是碰巧同名而已。当编译器看到一个类型的变量A调用Foo它时,它会进入并执行A.Foo(),因为该方法不是虚拟的,所以它不能被覆盖。类似地,当它看到B调用Foo它的类型的变量时,它会执行B.Foo(),而不管变量中包含的实例的实际类型。

另一方面,该Bar方法被定义为虚拟的,继承类可以(并且应该)覆盖它的实现。因此,无论何时调用Bar,无论是来自声明为Aor的变量,B实际调用的方法都必须在调用对象本身的层次结构中作为“最新”实现找到,不受用于引用对象的变量类型。

于 2013-02-06T14:23:00.570 回答
0

在类B中,您引入了一个与已经存在的new方法Foo(继承自 )具有相同名称和签名的方法A。所以B有两个同名的方法。如果你能避免它,那不是你会做的事情。

调用这两种方法Foo中的哪一种,取决于所使用的变量或表达式(类型为or )的编译时类型。AB

相比之下,方法Barvirtual。中只有一种方法BarB无论表达式的编译时类型是什么,它始终是被调用的“正确”覆盖。

于 2013-02-06T14:26:36.617 回答
0

写作

((A)clB).Foo()

就像说“把clB它当作一个A(如果可以的话)对待并给我”的结果Foo()。由于A具有非虚拟Foo方法,因此它执行A.Foo. 由于B'sFoo方法是一个 " new" 方法,因此在本例中不使用它。

写作

((A)clB).Bar()

是相似的——“把clB它当作一个A(如果可以的话)对待并给我”的结果Bar()。现在A有一个虚拟 Bar方法,这意味着它可以在基类中被覆盖。由于对象实际上是a B,它有一个overridefor Foo()B.Foo()因此被调用。

于 2013-02-06T14:27:21.340 回答
0
var clB = new B();
//Uses B's Foo method
Console.WriteLine(clB.Foo());    // output 1
//Uses A's Foo method since new was use to overload method
Console.WriteLine(((A)clB).Foo()); // output 5
//Uses B's Bar Method
Console.WriteLine(clB.Bar());    // output 1
//Uses B's Bar Method since A's Bar method was virtual
Console.WriteLine(((A)clB).Bar()); // output 1
于 2013-02-06T14:27:27.460 回答