解惑《你必须知道的.net》——C#继承关系中【方发表】的创建和调用

前言:

现在正在读《你必须知道的.net》(第二版)一书,看到IL语言那一章,将call、callvirt和calli时候,书中举了一个例子,是一个三层继承的例子,我一开始看的时候就有点懵。

代码如下:

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Father son = new Son();       
 6             son.DoWork();                 
 7             son.DoVirtualWork();          
 8             son.DoVirtualAll();           
 9 
10             Father aGrandson = new Grandson();  
11             aGrandson.DoWork();                 
12             aGrandson.DoVirtualWork();          
13             aGrandson.DoVirtualAll();           
14 
15             Console.Read();
16         }
17     }
18 
19     /// <summary>
20     /// Father类
21     /// </summary>
22     public class Father
23     {
24         public void DoWork()
25         {
26             Console.WriteLine("Father.DoWork()");
27         }
28 
29         //虚方法
30         public virtual void DoVirtualWork()
31         {
32             Console.WriteLine("Father.DoVirtualWork()");
33         }
34 
35         //虚方法
36         public virtual void DoVirtualAll()
37         {
38             Console.WriteLine("Father.DoVirtualAll()");
39         }
40     }
41 
42     /// <summary>
43     /// Son类
44     /// </summary>
45     public class Son : Father
46     {
47         //new 
48         public new void DoWork()
49         {
50             Console.WriteLine("Son.DoWork()");
51         }
52 
53         //new virtual
54         public new virtual void DoVirtualWork()
55         {
56             base.DoVirtualWork();
57             Console.WriteLine("Son.DoVirtualWork()");
58         }
59 
60         //override
61         public override void DoVirtualAll()
62         {
63             Console.WriteLine("Son.DoVirtualAll()");
64         }
65     }
66 
67     /// <summary>
68     /// Grandson类
69     /// </summary>
70     public class Grandson : Son
71     {
72         public override void DoVirtualWork()
73         {
74             base.DoVirtualWork();
75             Console.WriteLine("Grandson.DoVirtualWork()");
76         }
77 
78         public override void DoVirtualAll()
79         {
80             base.DoVirtualAll();
81             Console.WriteLine("Grandson.DoVirtualAll()");
82         }
83     }
View Code

代码看似很简单,Grandson继承了Son,Son继承了Father。main()方法中,声明了两个实例,调用实例方法。但是运行的结果却让我懵圈了,结果如下:

 

费尽周折俩小时想不出,我忽然想起书中一开始将继承的时候,将到了继承关系中方发表的创建,这才弄清楚了这个关系。

本文就以此例子大体讲讲在继承关系中,方发表是如何创建的。

 

创建方发表:

当一个对象初始化时,比如:Father son = new Son();  

系统会找到这个对象的类,将它的实例方法添加到方法表中。但是,如果这个类有父类,则先创建父类的。因为子类可能会override父类的方法。以Father son = new Son(); 为例:

 1 /// <summary>
 2     /// Father类
 3     /// </summary>
 4     public class Father
 5     {
 6         public void DoWork()
 7         {
 8             Console.WriteLine("Father.DoWork()");
 9         }
10 
11         //虚方法
12         public virtual void DoVirtualWork()
13         {
14             Console.WriteLine("Father.DoVirtualWork()");
15         }
16 
17         //虚方法
18         public virtual void DoVirtualAll()
19         {
20             Console.WriteLine("Father.DoVirtualAll()");
21         }
22     }
23 
24     /// <summary>
25     /// Son类
26     /// </summary>
27     public class Son : Father
28     {
29         //new 
30         public new void DoWork()
31         {
32             Console.WriteLine("Son.DoWork()");
33         }
34 
35         //new virtual
36         public new virtual void DoVirtualWork()
37         {
38             base.DoVirtualWork();
39             Console.WriteLine("Son.DoVirtualWork()");
40         }
41 
42         //override
43         public override void DoVirtualAll()
44         {
45             Console.WriteLine("Son.DoVirtualAll()");
46         }
47     }
View Code

根据以上代码,new一个Son类的对象的时候,会先找到Son类的父类——Father类,将Father的实例方法放在方法表中,就会有以下方发表结构:

(注:其实最先创建的是Object类的方法表,因为Object是所有类的父类,此处略过不讲)

接下来就会在将Son类的方法放入方发表中,此时要注意new和override。new其实相当于给方法重命名,虽然方法名和父类一样,但是是属于子类的另外一个方法了。override会重写父类方法,可以简单的理解为重写方法体。这是方发表就会变为:

所以,Father son = new Son();   最终的方发表会变成这样。

1             Father son = new Son();       
2             son.DoWork();          
3             son.DoVirtualWork();          
4             son.DoVirtualAll();          

执行以上代码时,会从方发表中自上而下查找,所以才会出现这种结果:

 

好了,继续跟着程序往下走,看看new Grandson()时,方发表又发生了哪些改变。

 1 /// <summary>
 2     /// Grandson类
 3     /// </summary>
 4     public class Grandson : Son
 5     {
 6         public override void DoVirtualWork()
 7         {
 8             base.DoVirtualWork();
 9             Console.WriteLine("Grandson.DoVirtualWork()");
10         }
11 
12         public override void DoVirtualAll()
13         {
14             base.DoVirtualAll();
15             Console.WriteLine("Grandson.DoVirtualAll()");
16         }
17     }
View Code

Grandson集成了Son类,在执行new Grandson()时,会先把Father的方法写入方发表,然后再是Son,这两个的方发表上文都画出了。最后在创建Grandson类的方发表。

Grandson类有两个实例方法,都重写了父类的虚方法。但是这两个方法有区别:DoVirtualWork()在Son类中已经被new,所以这里Grandson重写的DoVirtualWork()是Son类new之后的DoVirtualWork(),和Father类的DoVirtualWork()已经没有关系。而对DoVirtualAll()的重写将会修改Father类的DoVirtualAll()方法。

此时方发表将会是这样:

执行方法:

1 Father aGrandson = new Grandson();  
2 aGrandson.DoWork();              
3 aGrandson.DoVirtualWork();  
4 aGrandson.DoVirtualAll();  

执行时,从方发表自上而下获取方法,执行,才会出现以下结果:

 

总结:

其实我对方发表的理解,也就是《你必须知道的.net》一书中讲到的那一段话,最初看那一段话的时候感觉迷迷糊糊,但是结合着这个例子再来理解,就好多了。

如果本文有错误,后者表述不当,还请多多赐教、留言!

解惑《你必须知道的.net》——C#继承关系中【方发表】的创建和调用,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。