首页 新闻 会员 周边 捐助

【求帮助】简短的C#代码,大家给个结果,解释下。

1
[已解决问题] 解决于 2011-12-01 13:40

很简短的C#代码,如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 直接调度测试
{
class Program
{
public class Father
{
public void DoWork()
{
Console.WriteLine("Father.DoWork()");
}
public virtual void DoVirtualWork()
{
Console.WriteLine("Father.DoVirtualWork()");
}
}

public class Son : Father
{
public new void DoWork()
{
Console.WriteLine("Son.DoWork()");
}
public override void DoVirtualWork()
{
Console.WriteLine("Son.DoVirtualWork()");
}
public static void DoStaticWork()
{
Console.WriteLine("Son.DoStaticWork()");
}
}

static void Main(string[] args)
{
Father son2 = new Son();
//
son2.DoVirtualWork();
son2.DoWork();
}
}
}

程序的输出结果如下:

Son.DoVirtualWork()

Father.Dowork()

这里就有点迷糊了,哪位大侠给解释下,十万火急啊!!!!!!!!!!!

注:从CLR层面,肤浅的就不要了,谢谢!

DebugLZQ的主页 DebugLZQ | 菜鸟二级 | 园豆:205
提问于:2011-11-08 23:29
< >
分享
最佳答案
0

这答案谁告诉你的?有问题的。首先我觉得对方法表的理解有问题,每个类型都有自己的方法表,所以“Father类方法在方法表中位于Son方法的前面”这种说法有问题。CLR在调用一个方法时,已经知道这个方法是不是虚方法。如果不是虚方法,那么就去检查变量类型的method table,因此son2.DoWork()查找的是Father的MT(如果找不到那么会去基类里找),找到了就执行它(或者先JIT再执行)。如果是虚方法,那么会根据引用找到堆上的那个对象,根据对象的type pointer找到对象的真正类型(即GetType方法的返回类型),因此son2.DoVirtualWork()会直接查找Son的MT(如果找不到那么就去基类,这跟非虚方法是相同的)。你可以看看CLR VIA C#,里面讲的很清楚。

水牛刀刀 | 大侠五级 |园豆:6350 | 2011-11-09 11:58

CLR VIA C# 很不错的一本书,谢谢。

我赞同你的“类型都有自己的方法表”(其实,我也是这个意思- -),对于子类的方法表构成:我通过sos调试了dumpmt 看了,子类方法表包含父类的虚方法,不包含父类的实例方法。

事实证明,我理解出现偏差了,谢谢虾哥!!

DebugLZQ | 园豆:205 (菜鸟二级) | 2011-11-10 09:28

@DebugLZQ: 虾哥是谁。。。

水牛刀刀 | 园豆:6350 (大侠五级) | 2011-11-10 10:34
其他回答(6)
2

应经解决了,谢谢大家的反对与支持!

Father类型的引用,指向Son类型的实例;调用的应该是Son中得方法,但是在方法表中得偏移offset偏向于Father,而Father类方法在方法表中位于Son方法的前面。编译器调用方法表遵循最近原则(处于效率的考虑)。因此,son2调用DoWork方法的时候,Father的DoWork在前,且是实例方法,因此调用的Father的DoWork方法。当调用DoVirtualWork时,编译器发现Father类的DoVirtualWork是虚方法,递归调用直到方法表溢出,(由于函数调用方式是指向函数的指针,类似委托连式的方式,所以只有最后调用的函数返回),即发现子类Son实现了Father的虚方法,递归结束,调用Son的DoVirtualWork方法。

为了验证,我把Son中得DoVirtualWork的override改为new,这次调用的是Father中得DoVirtualWork方法。

DebugLZQ | 园豆:205 (菜鸟二级) | 2011-11-09 10:26
0
//基类型
Father son2 = new Son();

//首先 检查本类型(即Father)的方法DoVirtualWork,是不是虚或者抽象,如果不是//直接执行;如果是,再看子类(即Son)有没有重写,如果重写,则执行子类方法,如//果没有重写,执行本类型(即Father)的方法。
son2.DoVirtualWork();

//跟上面的规则一样
son2.DoWork();
心火 | 园豆:375 (菜鸟二级) | 2011-11-09 13:51
0

这个主要是new 和override的问题

new 是把父类的方法隐藏了,你把基类隐式转换成父类,调用的方法当然是父类的,因为是隐藏了,方法还在。

override 是把父类的方法重写,覆盖了,所以转换成父类的时候,还是看不见父类的方法,只能调用子类的。

熊猫祥 | 园豆:205 (菜鸟二级) | 2011-11-09 19:10
0

支持楼上

小小刀 | 园豆:1991 (小虾三级) | 2011-11-09 21:55
0

这个我也知道啊,可惜今天才看到啊,遗憾啊。。。

欢乐 | 园豆:332 (菜鸟二级) | 2011-11-22 17:12
0

学习了!

野马007 | 园豆:205 (菜鸟二级) | 2012-01-03 00:49
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册