为什么对这个感觉趣呢.因为以前写过两篇关于这个多态和重载混合起来很乱的调用情况分析,自从哪以后,我自认为随便乱写一些继承多态的代码都应该难不到我.但是今天看到一段代码有一个地方计算错误了,所以有必要写下来巩固一下,但是我之前总结的是没有问题的,今天就用以前总结的方法来看下面代码
代码来自 http://www.cnblogs.com/wangfupeng1988/p/3629312.html 博客
/// <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()"); } } }
下面Main里面的代码是这样的
//1 Father son = new Son(); son.DoWork(); son.DoVirtualWork(); son.DoVirtualAll(); //2 Father aGrandson = new Grandson(); aGrandson.DoWork(); Console.WriteLine("#"); aGrandson.DoVirtualWork(); Console.WriteLine("#"); aGrandson.DoVirtualAll();
我添加了两个分隔符号,方便阅读
先来看第1段的调用,
1.son.DoWork() 先看这个是否满足多态的条件(有继承,有父类引用,有虚方法重写),由于这个方法没有重写,所以不表现出多态,所以子类的new方法DoWork()是不调用的,这里调用父类的DoWork();所以显示Father.DoWork();
2.son.DoVirtualWork();这里也用同样没有方法的重写,所以不表现多态,直接调用父类方法
3.son.DoVirtualAll(); 这里满足条件了,所以这里表现出多态,应该调用子类的方法
这一段结果与上面的分析一样,看下一段,这里我就出错了.
先看
1.aGrandson.DoWork();这没有重写,不表现多态,所以显示Father的方法
2.aGrandson.DoVirtualWork() 这里有重写,是多态,那么显示子类的方法? 问题就在这里等会来分析
3.aGrandson.DoVirtualAll() 这里有重写,是多态,那么调用子类的方法.
这里我们重点来看一下第2,3两个步聚,首先第2步,是存重写,但是重写的是Son的new virtual void DoVirtualWork()方法,所以这一条继承链断了,所以这一步认为是 有父类引用,有虚方法重写,但是没有继承,所以这里不表现多态,那么直接调用Father的方法
然后看第3步,这里是有重写,有父类引用,有没有继承呢?这里有因为Son里面的没有用new关键字,所以这里也还算比较标准的多态调用,其实这里在运行时才去找到Son的DoVitualAll()方法的,平时最多的情况认为Grandson的父类是Father(是从这里代码来看);
这里问题看完了,那我们看一下这个
Console.WriteLine("#"); Son ss = new Grandson(); ss.DoVirtualWork();
这里有继承,有父类引用,有重写,那么应该调子类的方法
所以调Grandson.DoVirtualWork();由于这个调了父类的,所以再调Son的方法,Son又调了Father的方法,所以结果是
Father.DoVirtualWork()
Son.DoVirtualWork()
Grandson.DoVirtualWork()
都显示出来,差不多写到这里吧,方法还是好用的,我感觉分清楚了这三个条件,这些还是可以角决的.包括加入一些方法重载,只要分清处多态系和非多态系那就是没有问题的.
总结:
1.多态的三个条件,满足就调多态系方法,不满足就正常的调用(这里就可以说是调自身的方法)
2.分清为什么文中的第2步new断开的是继承,而不是其它条件.
3.父类引用指向子类,不管中间有多少层,我们分析的时候要注意,这两层是最重要的,但是也要注意一下,中间是否有断继承这类的情况