注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

淡忘邻人

二十七,始发愤

 
 
 

日志

 
 
 
 

CSDN C# Override new  

2010-05-21 22:16:39|  分类: C# |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

第18章 推理式的学习方式
有时候我们纠结迷茫,不知所措,其实最大的症结就在于不愿意深想,不愿意假设,不愿意宏观地去看待一切。虽然我们可能永远都无法从微软那里获得DotNet的源代码来研读,无法了解DotNet的内部机制,但并不代表我们不能自己对DotNet的内部机制进行假设和推断。要成为一个名优秀的软件工程师,学会使用推理的手法解决是一个非常有趣的过程,我们可以象江户川柯南一样在实际发生的事件中去推理真理。

什么是推理?推理就是由一个或几个已知的判断(前提),推导出一个未知的结论的思维过程。推理是一种形式逻辑。是研究事物形式及其规律和一些简单的逻辑方法的科学。其作用是从已知的知识得到未知的知识,特别是可以得到不可能通过感觉经验掌握的未知知识。

中国有一句老话:知其然,须求其所以然。在本章我们会使用一些常用的推理手法通过C#的一些在语法的定义和编译器的运行一系列的推理式学习,通过这个方式,读者不但可以更透彻的了解C#知识,更能学习到一种新型的学习模式,在将来遇到各种困惑又没有足够可以查阅资料的情况下,能得到正确的结果。

18.1 对概念的推理方法:为什么有哪些关键字?
18.1.1 溯因推理:为什么需要override和new两种多态方案
溯因推理是指根据事物发展过程所造成的结果。推断形成结果的一系列原因的整个逻辑思维过程,通俗的说就是从已知结果推断其原因的一种思维方式,其目的是得到一个最佳的解释,是一种典型的由果及因的方式。在逻辑结构上,它包括以下要素:

n 观察现象陈述

n 导致观察现象的可能原因即猜测性假说

在C#的面向对象中,override是使用比较多的关键字。但你是否知道为什么需要这两个关键字,并且当子类类型转为基类类型是,这两个关键字定义的成员将有什么不同吗?

在推理override和new的机制之前,我们再次回顾下这两个关键字的含义和用途。

n override:要扩展或修改继承的方法、属性、索引器或事件的抽象实现或虚实现,必须使用 override 修饰符(来自MSDN)。

n new:在用作修饰符时,new 关键字可以显式隐藏从基类继承的成员。隐藏继承的成员时,该成员的派生版本将替换基类版本(来自MSDN)。

在中文的术语中我们将override称为重写而new称为覆盖,并且MSDN在描述“何时使用 Override 和 New 关键字”时语焉不详,仅给出了以下的使用建议和原则:

在 C# 中,派生类可以包含与基类方法同名的方法,其定义的原则是:默认情况下,C# 方法为非虚方法。如果某个方法被声明为虚方法,则继承该方法的任何类都可以实现它自己的版本。若要使方法成为虚方法,必须在基类的方法声明中使用 virtual 修饰符。然后,派生类可以使用 override 关键字重写基虚方法,或使用 new 关键字隐藏基类中的虚方法。如果 override 关键字和 new 关键字均未指定,编译器将发出警告,并且派生类中的方法将隐藏基类中的方法。

为了解释这段另人头晕的文字,微软在MSDN中还给出了一个更令人膛目结舌的案例。不过为了让读者能快速清晰的了解这段文字想描述的含义,我将其总结为三条口诀:

n 任何非抽象(abstract)的实例方法在C#中默认是非虚拟(virtual)的

n 子类要定义和父类中非抽象(abstract)或非虚拟(virtual)的同名方法时,必须使用new(覆盖)关键字

n 子类要定义和父类中抽象或虚拟的同名方法时,必须使用override(重写)关键字

以下我们将实现一个继承的模型,这个模型中我将使用到override和new关键字,类的对象图如下

 

图Order类对象模型

以下我们将通过代码实现这个模型,请读者仔细观察和跟随实现。

我们首先定义一个Order类,该类只有两个方法,其中PrintInfo方法是虚拟的,其目的是输出一个简单的信息;PrintAuthor方法是非虚拟的,其目的是输出当前Windows操作系统登录人员的名字。

public class Order

{

public virtual void PrintInfo()

{

System.Console.WriteLine("Order...");

}

public void PrintAuhor()

{

System.Console.WriteLine(System.Environment.UserName);

}

}

然后我们从Order类继承一个派生类ShipOrder,该类使用override关键字重写了PrintInfo方法

public class ShipOrder : Order

{

public override void PrintInfo()

{

System.Console.WriteLine("ShipOrder");

}

}

我们再次从Order类继承一个派生类RoadOrder,该类使用override关键字重写了PrintInfo方法,并且使用new关键字覆盖了Order中非虚拟的PrintAuhor方法

public class RoadOrder : Order

{

public override void PrintInfo()

{

System.Console.WriteLine("RoadOrder");

}

public new void PrintAuhor()

{

System.Console.WriteLine(System.Environment.UserDomainName);

}

}

为展示这些类运行的结果,我们编写以下的代码

class Program

{

static void Main(string[] args)

{

new Order().PrintInfo();

new Order().PrintAuhor();

new ShipOrder().PrintInfo();

new ShipOrder().PrintAuhor();

new RoadOrder().PrintInfo();

new RoadOrder().PrintAuhor();

}

}

在查看显示结果前,笔者建议你自己先想像下运行的结果应该怎么样。下图是运行的结果

 

如果结果和你想像的一样,那么恭喜你,你对这两个关键字的基本用法已经非常明确了。但是现在我们想像下,如果将子类ShipOrder和RoadOrder强制的转为Order类型,并且再次调用PrintInfo和PrintAuthor方法会有什么情况出现呢?换句话说:将子类转换为父类的类型调用时,override和new方法是实现父类的行文还是自己自身的行为呢?

以下的运行代码演示如何进行这个测试

class Program

{

static void Main(string[] args)

{

new Order().PrintInfo();

new Order().PrintAuhor();

System.Console.WriteLine("----------------");

((Order)new ShipOrder()).PrintInfo();

((Order)new ShipOrder()).PrintAuhor();

System.Console.WriteLine("----------------");

((Order)new RoadOrder()).PrintInfo();

((Order)new RoadOrder()).PrintAuhor();

}

}

运行的结果如图,不知道和你想像的结果是否一致?

 

我们总结下运行的结果

当子类转换为父类,且以父类的形式进行方法调用时:override总是指向自己的实现,而new总是指向父类的实现。

那么为什么会出现这样的情况呢?请查看下目前我们所了解的事实:

当父类的方法定义为抽象(abstract)或虚拟(virtual)时,子类使用override关键字

当父类没有将方法定义为抽象(abstract)或虚拟(virtual)时,子类使用new关键字

现在我们将这个事实用表格的方式进行统计,统计的结果为: 父类方法的修饰
 Abstract
 virtual
 默认
 
子类调用父类方法
 失败
 成功
 成功
 
子类调用自己的方法
 成功
 成功
 成功
 
子类同名方法定义关键字
 override
 override
 new
 


从上面的表格我们可以清晰的得到如下的判断

n 因为override时候父类的成员有可能是abstract,所以调用其父类方法有50%的失败可能。

n 使用new关键字的时候,父类的成员必须是已经实现的,所以调用其父类决不可能会失败。

因此,当子类类型转换为基类类型时,为了确保最大的安全系数,使用override修饰的成员,都将指向子类自己的成员实现,而当成员是new定义的话,可以放心的调用父类类型中定义的成员了。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/shyleoking/archive/2010/05/20/5610612.aspx

  评论这张
 
阅读(515)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017