解惑《你必须知道的.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 [你必须知道的 ...
随机推荐
- day14(xml 编写及解析)
编写 xml的组成: 1.文档的声明 <?xml version='1.0' encoding='UTF-8' standalone='yes'> xml 表示标签的名字 encoding ...
- c++内存管理方式
概述 本章总结一些关于个人对内存管理的理解,主要包括如下内容: 内存管理原则 优秀的接口 智能指针的作用在哪里? 内存管理原则 学c++的同学都知道这个内存管理原则,就是“谁创建,谁释放”或者说“谁申 ...
- MFC中添加新的对话框
MFC工程中,除了系统自动生成的一些对话框之外,还需要根据自己的需求,添加新的对话框.这里总结下自己最近使用的方法. 首先,找到Resource View中自己新建的工程,然后右键,选择Add Cla ...
- HDU1237 简单计算器 2016-07-24 13:34 193人阅读 评论(0) 收藏
简单计算器 Problem Description 读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值. Input 测试输入包含若干测试用例,每个测试用例占一行,每行不超过 ...
- hdu 5014 异或序列
http://acm.hdu.edu.cn/showproblem.php?pid=5014 从最大的一个数开始找能配对使他们的异或值最大的一个数 最后输出 #include <cstdio&g ...
- 页面中的删除确认(ajax)、输入框中确认信息是否可用(ajax)的jquery代码
1.页面中的删除确认(ajax) <%@ page language="java" contentType="text/html; charset=UTF-8&qu ...
- mysql的sql性能分析器
MySQL 的SQL性能分析器主要用途是显示SQL执行的整个过程中各项资源的使用情况.分析器可以更好的展示出不良SQL的性能问题所在. mysql sql profile的使用方法 1.开启mysql ...
- 教程-Delphi调用百度地图API(XE8+WIN7)
unit U_map; interface //---------------------------------------------------// //----------COPY BY 无言 ...
- MVC-1.1 BundleConfig-ScriptBundle
App_Start中的BudleCnfig.cs中 bundles.Add(new ScriptBundle("~/bundles/jquery").Include( " ...
- Git提取两次提交的差异文件
1. 创建清单文件 获取两次提交之间的文件差异,并将文件清单保存到diff.txt文件中 Git diff --name-only 173d3010 18586360 > diff.txt 2. ...