解惑《你必须知道的.net》——C#继承关系中【方发表】的创建和调用
前言:
现在正在读《你必须知道的.net》(第二版)一书,看到IL语言那一章,将call、callvirt和calli时候,书中举了一个例子,是一个三层继承的例子,我一开始看的时候就有点懵。
代码如下:
class Program
{
static void Main(string[] args)
{
Father son = new Son();
son.DoWork();
son.DoVirtualWork();
son.DoVirtualAll(); Father aGrandson = new Grandson();
aGrandson.DoWork();
aGrandson.DoVirtualWork();
aGrandson.DoVirtualAll(); Console.Read();
}
} /// <summary>
/// Father类
/// </summary>
public class Father
{
public void DoWork()
{
Console.WriteLine("Father.DoWork()");
} //虚方法
public virtual void DoVirtualWork()
{
Console.WriteLine("Father.DoVirtualWork()");
} //虚方法
public virtual void DoVirtualAll()
{
Console.WriteLine("Father.DoVirtualAll()");
}
} /// <summary>
/// Son类
/// </summary>
public class Son : Father
{
//new
public new void DoWork()
{
Console.WriteLine("Son.DoWork()");
} //new virtual
public new virtual void DoVirtualWork()
{
base.DoVirtualWork();
Console.WriteLine("Son.DoVirtualWork()");
} //override
public override void DoVirtualAll()
{
Console.WriteLine("Son.DoVirtualAll()");
}
} /// <summary>
/// Grandson类
/// </summary>
public class Grandson : Son
{
public override void DoVirtualWork()
{
base.DoVirtualWork();
Console.WriteLine("Grandson.DoVirtualWork()");
} public override void DoVirtualAll()
{
base.DoVirtualAll();
Console.WriteLine("Grandson.DoVirtualAll()");
}
}
代码看似很简单,Grandson继承了Son,Son继承了Father。main()方法中,声明了两个实例,调用实例方法。但是运行的结果却让我懵圈了,结果如下:

费尽周折俩小时想不出,我忽然想起书中一开始将继承的时候,将到了继承关系中方发表的创建,这才弄清楚了这个关系。
本文就以此例子大体讲讲在继承关系中,方发表是如何创建的。
创建方发表:
当一个对象初始化时,比如:Father son = new Son();
系统会找到这个对象的类,将它的实例方法添加到方法表中。但是,如果这个类有父类,则先创建父类的。因为子类可能会override父类的方法。以Father son = new Son(); 为例:
/// <summary>
/// Father类
/// </summary>
public class Father
{
public void DoWork()
{
Console.WriteLine("Father.DoWork()");
} //虚方法
public virtual void DoVirtualWork()
{
Console.WriteLine("Father.DoVirtualWork()");
} //虚方法
public virtual void DoVirtualAll()
{
Console.WriteLine("Father.DoVirtualAll()");
}
} /// <summary>
/// Son类
/// </summary>
public class Son : Father
{
//new
public new void DoWork()
{
Console.WriteLine("Son.DoWork()");
} //new virtual
public new virtual void DoVirtualWork()
{
base.DoVirtualWork();
Console.WriteLine("Son.DoVirtualWork()");
} //override
public override void DoVirtualAll()
{
Console.WriteLine("Son.DoVirtualAll()");
}
}
根据以上代码,new一个Son类的对象的时候,会先找到Son类的父类——Father类,将Father的实例方法放在方法表中,就会有以下方发表结构:
(注:其实最先创建的是Object类的方法表,因为Object是所有类的父类,此处略过不讲)

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

所以,Father son = new Son(); 最终的方发表会变成这样。
Father son = new Son();
son.DoWork();
son.DoVirtualWork();
son.DoVirtualAll();
执行以上代码时,会从方发表中自上而下查找,所以才会出现这种结果:

好了,继续跟着程序往下走,看看new Grandson()时,方发表又发生了哪些改变。
/// <summary>
/// Grandson类
/// </summary>
public class Grandson : Son
{
public override void DoVirtualWork()
{
base.DoVirtualWork();
Console.WriteLine("Grandson.DoVirtualWork()");
} public override void DoVirtualAll()
{
base.DoVirtualAll();
Console.WriteLine("Grandson.DoVirtualAll()");
}
}
Grandson集成了Son类,在执行new Grandson()时,会先把Father的方法写入方发表,然后再是Son,这两个的方发表上文都画出了。最后在创建Grandson类的方发表。
Grandson类有两个实例方法,都重写了父类的虚方法。但是这两个方法有区别:DoVirtualWork()在Son类中已经被new,所以这里Grandson重写的DoVirtualWork()是Son类new之后的DoVirtualWork(),和Father类的DoVirtualWork()已经没有关系。而对DoVirtualAll()的重写将会修改Father类的DoVirtualAll()方法。
此时方发表将会是这样:

执行方法:
Father aGrandson = new Grandson();
aGrandson.DoWork();
aGrandson.DoVirtualWork();
aGrandson.DoVirtualAll();
执行时,从方发表自上而下获取方法,执行,才会出现以下结果:

总结:
其实我对方发表的理解,也就是《你必须知道的.net》一书中讲到的那一段话,最初看那一段话的时候感觉迷迷糊糊,但是结合着这个例子再来理解,就好多了。
如果本文有错误,后者表述不当,还请多多赐教、留言!
解惑《你必须知道的.net》——C#继承关系中【方发表】的创建和调用的更多相关文章
- 读《你必须知道的.NET》继承本质论 Bird bird=new Chicken()
我们创建如下的三层继承层次类. public abstract class Animal { public abstract void ShowType(); } public class Bird ...
- [你必须知道的.NET]第二十回:学习方法论
说在,开篇之前 本文,源自我回答刚毕业朋友关于.NET学习疑惑的回复邮件. 本文,其实早计划在<你必须知道的.NET>写作之初的后记部分,但是因为个中原因未能如愿,算是补上本书的遗憾之一. ...
- c语言学习书籍推荐《C语言学习路线图•C语言必须知道的300个问题》下载
下载地址:点我 <C语言学习路线图•C语言必须知道的300个问题>以基础知识为框架,介绍了c语言各部分知识所对应的常见开发疑难问题,并作了透彻地解析.<C语言学习路线图•C语言必须知 ...
- C#继承关系中【方发表】的创建和调用
—C#继承关系中[方发表]的创建和调用 Insus.NET实现一个最炫最原创的验证码.你可以从下面的一步一步的演译. 实现一个验证码,需要了解的是,它最基本是随机产生字符串:<在ASP.NET ...
- [你必须知道的.NET]第二十七回:interface到底继承于object吗?
发布日期:2009.03.05 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 在.NET世界里,我们常常听到的一句话莫过于“S ...
- 《你必须知道的.NET》读书笔记一:小OO有大智慧
此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.对象 (1)出生:系统首先会在内存中分配一定的存储空间,然后初始化其附加成员,调用构造函数执行初 ...
- MVC中你必须知道的13个扩展点
MVC中你必须知道的13个扩展点 pasting 转:http://www.cnblogs.com/kirinboy/archive/2009/06/01/13-asp-net-mvc-extensi ...
- 前端开发必须知道的JS(二) 闭包及应用
http://www.cnblogs.com/ljchow/archive/2010/07/06/1768749.html 在前端开发必须知道的JS(一) 原型和继承一文中说过下面写篇闭包,加之最近越 ...
- [你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理
原文地址:http://kb.cnblogs.com/page/42318/ 系列文章导航: [你必须知道的.NET] 开篇有益 [你必须知道的.NET] 第一回:恩怨情仇:is和as [你必须知道的 ...
随机推荐
- 3D indoor map positioning with a smartphone image
menu 1. 基于Tango的三维建模技术(SLAM)(视觉SLAM,RGBD单目深度摄像机+罗盘仪)导出或不导出->Android 三维游戏开发技术(普通Android手机) 2. 基于An ...
- hibernate中常用的Hql语句总结
// HQL: Hibernate Query Language. // 特点: // >> 1,与SQL相似,SQL中的语法基本上都可以直接使用. // >> 2,SQL查询 ...
- Java类与类之间的继承关系
Java父类与子类继承关系,调用的各种关系 示例一(子类调用父类函数): // 定义一类 A public class A { // 此方法打印一句话 public void a() { System ...
- 【WinRT】获取 Uri 中的参数(QueryString)键值对
在控制台或者其它类型的项目中,可以添加 System.Web,使用以下代码来获取一个 Uri 中的参数 Uri uri = new Uri("http://www.cnblogs.com/h ...
- ASP.Net C#---Excel导入导入后台方法
https://www.cnblogs.com/chendaye/p/10693983.html 这里写了Excel的导入导入方法, 后台我用的是MVC 以及 C#语句用来在后台做接受和输出数据 / ...
- .NET 日志工具 log4net使用
1.NuGet安装log4net. 2.修改配置文件 <?xml version="1.0"?> <configuration> <configSec ...
- jwt的ASP.NET MVC 身份验证
Json Web Token(jwt) 一种不错的身份验证及授权方案,与 Session 相反,Jwt 将用户信息存放在 Token 的 payload 字段保存在客户端,通过 RSA 加密 ...
- 将GridView的数据导出Excel
HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename ...
- hdu 5500 Reorder the Books
http://acm.hdu.edu.cn/showproblem.php?pid=5500 Reorder the Books Time Limit: 4000/2000 MS (Java/Othe ...
- css小点心
本文由作者邹欣华授权网易云社区发布. 有一个在邮件中用饼图直观地显示用户的各项消费比例的需求.邮箱中不能用js,纯css实现饼图,只能通过后端模版渲染数据,所以数据越少越简单越好. 想到css3的tr ...