abstract virtaul override new 及多态
abstract
abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。
抽象类具有以下特性:
抽象类不能实例化。
抽象类可以包含抽象方法和抽象访问器。
不能用 sealed(C# 参考) 修饰符修改抽象类,因为 sealed 会使得抽象类无法被继承。
- 从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。
抽象方法具有以下特性:
抽象方法是隐式的虚方法。
只允许在抽象类中使用抽象方法声明。(即抽象方法只能在抽象类中)
因为抽象方法声明不提供实际的实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号 ({ })。
例如:
public abstract void MyMethod();
实现由一个重写方法override(C# 参考)提供,此重写方法是非抽象类的一个成员。
除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。
在静态属性上使用 abstract 修饰符是错误的。
- 在派生类中,通过包括使用 override 修饰符的属性声明,可以重写抽象的继承属性。
virtaul
virtaul 关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写(为了被重写abstract 及virtaul 都不能是私有的)
调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。
默认情况下,方法是非虚拟的。不能重写非虚方法。
virtual 修饰符不能与 static、abstract, private 或 override 修饰符一起使用。
除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。
在静态属性上使用 virtual 修饰符是错误的。
- 通过包括使用 override 修饰符的属性声明,可在派生类中重写虚拟继承属性。
派生类
在 C# 中,派生类可以包含与基类方法同名的方法。
在 C# 中,派生类中方法的名称可与基类中方法的名称相同。可通过使用 new 和 override 关键字指定方法互动的方式。override 修饰符 extends 基类方法,且 new 修饰符将其“隐藏”起来。
New关键字主要用来区别派生类和基类同名方法的选择问题,通过隐藏基类方法,达到使编译器调用正确的方法的目的。Override主要用来对基类的方 法和虚方法进行重写。(如果A基类中有虚方法a,那派生类B,C分别用override及new重写a,若B,C在实例化时使用的类型是A定义的,那使用调用a时发布是B中方法,A中方法,若B,C在实例化时使用的类型其本身派生类的类型定义的,那使用调用a时发布是B中方法,C中方法)
如果希望派生成员具有与基类中的成员相同的名称,但又不希望派生成员参与虚调用,则可以使用 new 关键字。new 关键字放置在要替换的类成员的返回类型之前
使用新成员隐藏基类成员(其实就是new与override的区别,从文字上来说一个是隐藏一个是重写)
如果希望派生成员具有与基类中的成员相同的名称,但又不希望派生成员参与虚调用,则可以使用 new 关键字。new 关键字放置在要替换的类成员的返回类型之前。以下代码提供了一个示例:
public class BaseClass
{
public void DoWork() { WorkField++; }
public int WorkField;
public int WorkProperty
{
get { return 0; }
}
}
public class DerivedClass : BaseClass
{
public new void DoWork() { WorkField++; }
public new int WorkField;
public new int WorkProperty
{
get { return 0; }
}
}
通过将派生类的实例强制转换为基类的实例,仍然可以从客户端代码访问隐藏的基类成员。例如:
DerivedClass B = new DerivedClass(); B.DoWork(); // Calls the new method. BaseClass A = (BaseClass)B; A.DoWork(); // Calls the old method.
从派生类访问基类虚拟成员
public class Base
{
public virtual void DoWork() {/*...*/ }
}
public class Derived : Base
{
public override void DoWork()
{
//Perform Derived's work here //... // Call DoWork on base class base.DoWork();
}
}
重写和方法选择
当在类中指定方法时,如果有多个方法与调用兼容(例如,存在两种同名的方法,并且其参数与传递的参数兼容),则 C# 编译器将选择最佳方法进行调用。下面的方法将是兼容的:
publicclass Derived : Base
{
publicoverridevoid DoWork(int param) { }
publicvoid DoWork(double param) { }
}
A.DoWork(); // Calls the old method.
阻止派生类重写虚拟成员
无论在虚拟成员和最初声明虚拟成员的类之间已声明了多少个类,虚拟成员永远都是虚拟的。如果类 A 声明了一个虚拟成员,类 B 从 A 派生,类 C 从类 B 派生,则类 C 继承该虚拟成员,并且可以选择重写它,而不管类 B 是否为该成员声明了重写。以下代码提供了一个示例:
public class A
{
public virtual void DoWork() { }
}
public class B : A
{
public override void DoWork() { }
}
派生类可以通过将重写声明为 sealed 来停止虚拟继承。 这需要在类成员声明中的 override 关键字前面放置 sealed 关键字。以下代码提供了一个示例:
public class C : B
{
public sealed override void DoWork() { }
}
在上一个示例中,方法 DoWork 对从 C 派生的任何类都不再是虚拟方法。即使它们转换为类型 B 或类型 A,它对于 C 的实例仍然是虚拟的。通过使用 new 关键字,密封的方法可以由派生类替换,如下面的示例所示:
public class D : C
{
public new void DoWork() { }
}
在此情况下,如果在 D 中使用类型为 D 的变量调用 DoWork,被调用的将是新的 DoWork。如果使用类型为 C、B 或 A 的变量访问 D 的实例,对 DoWork 的调用将遵循虚拟继承的规则,即把这些调用传送到类 C 的 DoWork 实现。
将 virtual 方法声明为 abstract
// compile with: /target:librarypublicclass D
{
public virtual void DoWork(int i)
{
// Original implementation.
}
}
public abstract class E : D
{
public abstract override void DoWork(int i);
}
publicclass F : E
{
public override void DoWork(int i)
{
// New implementation.
}
}
如果将 virtual 方法声明为 abstract,则该方法对于从抽象类继承的所有类而言仍然是虚方法。继承抽象方法的类无法访问该方法的原始实现。在前面的示例中,类 F 上的 DoWork 无法调用类 D 上的 DoWork。在此情况下,抽象类可以强制派生类为虚方法提供新的方法实现。
密封类和类成员
通过在类定义前面放置关键字 sealed,可以将类声明为密封类。例如:
public sealed class D
{
// Class members here.
}
密封类不能用作基类。因此,它也不能是抽象类。密封类禁止派生。由于密封类从不用作基类,所以有些运行时优化可以使对密封类成员的调用略快。
在对基类的虚成员进行重写的派生类上的类成员、方法、字段、属性或事件可以将该成员声明为密封成员。在用于以后的派生类时,这将取消成员的虚效果。方法是在类成员声明中将 sealed 关键字置于 override 关键字的前面。例如:
多态 (上面的都是铺垫)
在运行时,在方法参数和集合或数组等位置,派生类的对象可以作为基类的对象处理。发生此情况时,该对象的声明类型不再与运行时类型相同。
基类可以定义并实现虚方法,派生类可以重写这些方法,即派生类提供自己的定义和实现。在运行时,客户端代码调用该方法,CLR 查找对象的运行时类型,并调用虚方法的重写方法。因此,你可以在源代码中调用基类的方法,但执行该方法的派生类版本。
虚方法/抽象方法/接口都是可以实现多态的(因为MSDN上的例子是用抽象方法写的,所以网上一些人说只有抽象方法才能实现多态,这一点是错误的,特别说明下)
直接看代码
class Program { interface IdoWork { void Do(); } abstract class DoWork //若使用IdoWork会有一样的结果 { public abstract void Do(); } class DoMyWork { public virtual void Do() { Console.WriteLine("DoMyWork"); } } class Do1:DoWork { public override void Do() { Console.WriteLine("Do1"); } } class Do2 : DoWork { public override void Do() { Console.WriteLine("Do2"); } } class MyDo1 : DoMyWork { public override void Do() { Console.WriteLine("MyDo1"); } } class MyDo2 : DoMyWork { public override void Do() { Console.WriteLine("MyDo2"); } } class MyDo3 : DoMyWork { public new void Do() { Console.WriteLine("MyDo3"); } } static void Main(string[] args) { contact ct1 = new class1(); contact ct2 = new class2(); class2 ct3 = new class2(); ct1.prinf(); ct2.prinf(); ct3.prinf(); Console.ReadKey(); List<DoWork> Dos = new List<DoWork>(); Dos.Add(new Do1()); Dos.Add(new Do2()); Dos[].Do(); Dos[].Do(); Console.ReadKey(); List<DoMyWork> MyDos = new List<DoMyWork>(); MyDos.Add(new MyDo1()); MyDos.Add(new MyDo2()); MyDos.Add(new MyDo3()); MyDos[].Do(); MyDos[].Do(); MyDos[].Do(); Console.ReadKey(); } } abstract public class contact { public virtual void prinf() { Console.WriteLine("这是虚方法"); } } public class class1 : contact { public override void prinf() { Console.WriteLine("这是新的方法"); } } public class class2 : contact { public new void prinf() { Console.WriteLine("这是另一个新的方法"); } } }
abstract virtaul override new 及多态的更多相关文章
- sealed、new、virtual、abstract与override 趣解
1. sealed——“断子绝孙” 密封类不能被继承.密封方法可以重写基类中的方法,但其本身不能在任何派生类中进一步重写.当应用于 方法或属性时,sealed修饰符必须始终与override一起使用. ...
- sealed、new、virtual、abstract与override 总结
1. sealed——“断子绝孙” 密封类不能被继承.密封方法可以重写基类中的方法,但其本身不能在任何派生类中进一步重写.当应用于方法或属性时,sealed修饰符必须始终与override一起使用. ...
- abstract、override、new、virtual、sealed使用和示例
abstract修饰类名为抽象类,修饰方法为抽象方法.如果一个类为抽象类,则这个类智能是其他某个类的基类.抽象方法在抽象类中没有函数体.抽象类中的抽象方法是没有方法体的,继承其的子类必须实现抽象类的抽 ...
- c#中abstract、override、new、virtual、sealed使用
abstract 修饰类名为抽象类,修饰方法为抽象方法.如果一个类为抽象类,则这个类智能是其他某个类的基类.抽象方法在抽象类中没有函数体.抽象类中的抽象方法是没有方法体的,继承其的子类必须实现 ...
- c#中abstract、override、new、virtual、sealed使用和示例
原文地址:http://blog.csdn.net/richerg85/article/details/7407544 abstract 修饰类名为抽象类,修饰方法为抽象方法.如果一个类为抽 ...
- sealed,new,virtual,abstract与override关键字的区别?
1. sealed——“断子绝孙” 密封类不能被继承.密封方法可以重写基类中的方法,但其本身不能在任何派生类中进一步重写.当应用于方法或属性时,sealed修饰符必须始终与override一起使用. ...
- knowing abstract,virtual,override,new
If a class has at least one member which modified by "abstract",this class is an abstract ...
- c#中virtual, abstract和override的区别和用法
virtual是把一个方法声明为虚方法,使派生类可重写此方法,一般建立的方法是不能够重写的,譬如类A中有个方法protected void method(){ 原代码....;}类B继承自类A,类B能 ...
- C# selecd,new,virtual,abstract与override
本文大部分内容摘自 <.NET开发专家·亮剑.NET : .NET深入体验与实战精要> 博主只是搬运工,不喜勿喷. 关于虚方法,抽象类这一部分一直不是太清楚,目前的工作中也接触不到这些. ...
随机推荐
- JSON 格式介绍
转自:http://www.json.org/json-zh.html JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式. 易于人阅读和编写.同时也易于机器 ...
- 【mysql】索引的优化
写在前面的话 查询容易,优化不易,且写且珍惜 mysql结构 从MySQL逻辑架构来看,MySQL有三层架构,第一层连接,第二层查询解析.分析.优化.视图.缓存,第三层,存储引擎 MySQL有哪些索引 ...
- ubuntu16.04下opencv安装笔记和例程
问题: 最近重装了系统,需要重新配置opencv2.4.13,配置完成后每次都出现cmake error,google了报错,尝试了各种方法,都未解决问题,于是重新git clone 了opencv2 ...
- DirectX API 编程起步 #02 窗口的诞生
在这篇文章里我们先用 windows API 制作一个窗口出来,以后再用 DirectX API 渲染的东西就会显示在这里,控制台那黑白的画面肯定是没法用的. 每次的代码都会更新到Github 首先贴 ...
- SSIS XML source demo
以下是一个使用xml作为source的SSIS package示例: 自动生成的xsd.把两个结点merge join成一条记录. 示例XML如下: <?xml version="1. ...
- 【MVC 4】7.SportsSore:完成购物车
作者:[美]Adam Freeman 来源:<精通ASP.NET MVC 4> 本文将继续构建 SportsStore 示例应用程序.在上一章中,添加了对购物车的基本支持,现在打 ...
- 51nod-1537 1537 分解(矩阵快速幂+找规律)
题目链接: 1537 分解 问(1+sqrt(2)) ^n 能否分解成 sqrt(m) +sqrt(m-1)的形式 如果可以 输出 m%1e9+7 否则 输出no Input 一行,一个数n.( ...
- Spring addFlashAttribute
redirectAttributes.addFlashAttribute("result",accountModel); 用这个可以绑定session 但是只能用一次,可以避免最后 ...
- javascript边角知识
1.组织默认事件 阻止默认事件,h5默认的input type='date'在某些浏览器和android设备上没有效果,这时要调用h5+的时间选择器,但是要组织input默认的click事件,代码如下 ...
- iOS原生地图开发详解
在上一篇博客中:http://my.oschina.net/u/2340880/blog/414760.对iOS中的定位服务进行了详细的介绍与参数说明,在开发中,地位服务往往与地图框架结合使用,这篇博 ...