C# c类铸件#
这是c代码 产量C# c类铸件#,c#,asp.net,oop,casting,C#,Asp.net,Oop,Casting,这是c代码 产量 Console.WriteLine(((A)clB).Foo()); // output 5 <<<-- Console.WriteLine(((A)clB).Bar()); // output 1 Console.WriteLine(((A)clB.Foo());//输出5我假设 var clB = new B(); Foo和Bar方法之间的区别在于Bar使用继承和多态性来决定调用什么实现,而Foo方法隐藏了它的原始实现 总之,一个词,a.Foo()和B
Console.WriteLine(((A)clB).Foo()); // output 5 <<<--
Console.WriteLine(((A)clB).Bar()); // output 1
Console.WriteLine(((A)clB.Foo());//输出5我假设
var clB = new B();
Foo
和Bar
方法之间的区别在于Bar
使用继承和多态性来决定调用什么实现,而Foo
方法隐藏了它的原始实现
总之,一个词,a.Foo()
和B.Foo()
是完全不相关的,它们只是碰巧有相同的名字。当编译器看到a
类型的变量调用Foo
时,它进入并执行a.Foo()
,因为该方法不是虚拟的,所以无法重写。类似地,当它看到类型为B
的变量调用Foo
时,它执行B.Foo()
,而不管变量中包含的实例的实际类型如何
另一方面,Bar
方法被定义为virtual,继承类可以(并且应该)覆盖它的实现。因此,每当调用Bar
,无论它来自声明为a
或B
的变量,实际调用的方法必须作为调用对象本身层次结构中的“最新”实现找到,不受用于引用对象的变量类型的影响。在类B
中,您引入了一个新的方法Foo
,其名称和签名与已有的方法相同(继承自a
)。所以B
有两个同名的方法。如果你能避免的话,你是不会这么做的
调用的两个方法Foo
中的哪一个取决于所使用的变量或表达式(类型A
或B
)的编译时类型
相比之下,Bar
方法是virtual
。在B
中只有一种方法Bar
。无论表达式的编译时类型是什么,调用的总是“正确”的重写。
((A)clB).Foo()
((A)clB).Bar()
就像说“把clB
当作A
(如果可以的话)来对待,然后告诉我Foo()的结果
”。因为A
有一个非虚拟的Foo
方法,所以它执行A.Foo
。由于B
的Foo
方法是一种“新的
”方法,因此在本例中不使用它
书写
((A)clB).Foo()
((A)clB).Bar()
类似-“将clB
视为A
(如果可以)并将Bar()的结果告诉我。”。现在A
有一个虚拟的Bar
方法,这意味着它可以在基类中被重写。由于对象实际上是一个B
,它对Foo()
有一个重写,因此调用B.Foo()
。你用new重写B
classFoo
方法,因此它隐藏了classa
@Romoku的Foo方法:它根本不重写Foo。这就是重点。顺便说一句,在不使用new关键字的情况下,您将观察到相同的行为。@JonSkeet重载了,我很抱歉。@Romoku:甚至没有重载。你:这个方法不是虚拟的,所以它不能被继承,我想你的意思是“不能被重写”。所有方法都是由派生类型继承的(尽管其中一些方法可能无法访问(比如它们是私有的)。更详细地说,如果不指定virtual
,则将其视为静态绑定,这意味着调用的方法实现是在编译时确定的。如果它是虚拟的
,则它使用动态绑定,并在运行时根据实际对象实例确定调用的方法实现。@JeppeStigNielsen是的,这就是我的意思。实现是继承的,但更改它(覆盖)的权利不是继承的。您可以找到第二个问题的答案
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