我一直认为base.Something
相当于((Parent)this).Something
,但显然事实并非如此。我认为重写方法消除了调用原始虚方法的可能性。
为什么第三个输出不同?
void Main() {
Child child = new Child();
child.Method(); //output "Child here!"
((Parent)child).Method(); //output "Child here!"
child.BaseMethod(); //output "Parent here!"
}
class Parent {
public virtual void Method() {
Console.WriteLine("Parent here!");
}
}
class Child : Parent {
public override void Method() {
Console.WriteLine ("Child here!");
}
public void BaseMethod() {
base.Method();
}
}
答案 0 :(得分:5)
因为在BaseMethod
中您显式地使用base
关键字在基类中调用该方法。在课程中调用Method()
和base.Method()
之间存在差异。
在base
关键字的文档中,它说(除其他外)它可以用于调用已被另一个方法覆盖的基类上的方法。
答案 1 :(得分:3)
((Parent)this).foo
对于虚方法foo仍然/始终是虚方法调用。将从类的虚方法表中查找目标地址,该表将始终位于对象实例类型的最繁琐的实现中。您可以根据需要将其强制转换为父级,但这不会更改用于在运行时调度调用的vtable。
base
关键字将调用解析为非虚拟调用,以便您可以从后代实现中访问祖先实现。运行时没有地址查找,地址在编译时解析。
答案 2 :(得分:3)
C#语言规范:
在编译时, base-access 表格形式base.I和 base [E]完全被评估为 他们写的((B)这个。)我和 ((B)this)[E],其中B是基数 其中的类或结构的类 构造发生。
base-access 引用a时 虚函数成员(一种方法, 属性或索引器), 确定哪个功能成员 在运行时调用(第7.4.4节)是 改变。函数成员是 调用是通过查找来确定的 大多数派生的实现(§10.6.3) 函数成员的关于 B(而不是相对于 这样的运行时类型 通常在非基础访问中。)
即。 base.Something相当于((Parent)this)。但只有非虚拟成员才有,但语义不同。
答案 3 :(得分:2)
我相信你误解了base.Something()
。 base
专门调用基类(可能)覆盖方法或属性的实现。 From MSDN:
base关键字用于访问 来自内部的基类成员 派生类:
在基类上调用一个方法 已被另一种方法覆盖。已被另一种方法覆盖。
请注意((Parent)this).Something()
只会影响您使用new
隐藏方法而不是虚拟override
时所调用的内容。
答案 4 :(得分:1)
将子项作为父类型进行转换不会更改将要调用的函数,因为它们已在对象上被覆盖。这是继承之美(多态)的一部分。
在BaseMethod中你调用base.Method,这是一种访问父函数的方法(如果你需要)但是如果你有一个Shape类型的数组,并且在它中是不同的形状子类,你想要.Draw()方法调用子类而不是超类方法(默认情况下)。
答案 5 :(得分:0)