c#中的类铸造

本文关键字: | 更新日期: 2023-09-27 17:58:04

这是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

我们如何得到这个输出。有人能在这里解释一下选班的过程吗。

更新:

这如何显示阴影和覆盖之间的差异

c#中的类铸造

我假设

var clB = new B();

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

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

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

在类B中,您引入了一个new方法Foo,该方法与现有方法(继承自A)具有相同的名称和签名。所以B有两个同名的方法。如果你能避免的话,你不会这么做。

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

相反,方法BarvirtualB中只有一种方法Bar。无论表达式的编译时类型是什么,调用的始终是"正确"的重写。

写入

((A)clB).Foo()

就像说"把clB当作A(如果可以的话),然后给我Foo()的结果"。由于A具有非虚拟Foo方法,因此它执行A.Foo。由于BFoo方法是"new"方法,因此在本例中不使用它。

写入

((A)clB).Bar()

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

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
相关文章:
  • 没有找到相关文章