abstract

abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。

抽象类具有以下特性:

  • 抽象类不能实例化。

  • 抽象类可以包含抽象方法和抽象访问器。

  • 不能用 sealed(C# 参考) 修饰符修改抽象类,因为 sealed 会使得抽象类无法被继承。

  • 从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。

抽象方法具有以下特性:

  • 抽象方法是隐式的虚方法。

  • 只允许在抽象类中使用抽象方法声明。(即抽象方法只能在抽象类中)

  • 因为抽象方法声明不提供实际的实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号 ({ })。

    • 例如:

      public abstract void MyMethod();
  • 实现由一个重写方法override(C# 参考)提供,此重写方法是非抽象类的一个成员。

  • 在抽象方法声明中使用 static 或 virtual 修饰符是错误的。

除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。

  • 在静态属性上使用 abstract 修饰符是错误的。

  • 在派生类中,通过包括使用 override 修饰符的属性声明,可以重写抽象的继承属性。

virtaul

virtaul 关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写(为了被重写abstract 及virtaul 都不能是私有的)

调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。

默认情况下,方法是非虚拟的。不能重写非虚方法。

virtual 修饰符不能与 static、abstract, private 或 override 修饰符一起使用。

除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。

  • 在静态属性上使用 virtual 修饰符是错误的。

  • 通过包括使用 override 修饰符的属性声明,可在派生类中重写虚拟继承属性。

派生类

在 C# 中,派生类可以包含与基类方法同名的方法。

  • 基类方法必须定义为 virtual

  • 如果派生类中的方法前面没有 new 或 override 关键字,则编译器将发出警告,该方法将有如存在 new 关键字一样执行操作。

  • 如果派生类中的方法前面带有 new 关键字,则该方法被定义为独立于基类中的方法。(使用 new 关键字可告诉编译器您的定义将隐藏基类中包含的定义。这是默认行为。)

  • 如果派生类中的方法前面带有 override 关键字,则派生类的对象将调用该方法,而不是调用基类方法。

  • 可以从派生类中使用 base 关键字调用基类方法。

  • override、virtual 和 new 关键字还可以用于属性、索引器和事件中。

在 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 及多态的更多相关文章

  1. sealed、new、virtual、abstract与override 趣解

    1. sealed——“断子绝孙” 密封类不能被继承.密封方法可以重写基类中的方法,但其本身不能在任何派生类中进一步重写.当应用于 方法或属性时,sealed修饰符必须始终与override一起使用. ...

  2. sealed、new、virtual、abstract与override 总结

    1. sealed——“断子绝孙” 密封类不能被继承.密封方法可以重写基类中的方法,但其本身不能在任何派生类中进一步重写.当应用于方法或属性时,sealed修饰符必须始终与override一起使用. ...

  3. abstract、override、new、virtual、sealed使用和示例

    abstract修饰类名为抽象类,修饰方法为抽象方法.如果一个类为抽象类,则这个类智能是其他某个类的基类.抽象方法在抽象类中没有函数体.抽象类中的抽象方法是没有方法体的,继承其的子类必须实现抽象类的抽 ...

  4. c#中abstract、override、new、virtual、sealed使用

    abstract     修饰类名为抽象类,修饰方法为抽象方法.如果一个类为抽象类,则这个类智能是其他某个类的基类.抽象方法在抽象类中没有函数体.抽象类中的抽象方法是没有方法体的,继承其的子类必须实现 ...

  5. c#中abstract、override、new、virtual、sealed使用和示例

    原文地址:http://blog.csdn.net/richerg85/article/details/7407544 abstract      修饰类名为抽象类,修饰方法为抽象方法.如果一个类为抽 ...

  6. sealed,new,virtual,abstract与override关键字的区别?

    1. sealed——“断子绝孙” 密封类不能被继承.密封方法可以重写基类中的方法,但其本身不能在任何派生类中进一步重写.当应用于方法或属性时,sealed修饰符必须始终与override一起使用. ...

  7. knowing abstract,virtual,override,new

    If a class has at least one member which modified by "abstract",this class is an abstract ...

  8. c#中virtual, abstract和override的区别和用法

    virtual是把一个方法声明为虚方法,使派生类可重写此方法,一般建立的方法是不能够重写的,譬如类A中有个方法protected void method(){ 原代码....;}类B继承自类A,类B能 ...

  9. C# selecd,new,virtual,abstract与override

    本文大部分内容摘自  <.NET开发专家·亮剑.NET : .NET深入体验与实战精要> 博主只是搬运工,不喜勿喷. 关于虚方法,抽象类这一部分一直不是太清楚,目前的工作中也接触不到这些. ...

随机推荐

  1. Effective Java 16 Favor composition over inheritance

    Inheritance disadvantage Unlike method invocation, inheritance violates encapsulation. Since you don ...

  2. 迷宫问题求解之“A*搜索”(二)

    摘要:在迷宫问题求解之"穷举+回溯"(一)这篇文章中采用"穷举+回溯"的思想,虽然能从迷宫的入口到出口找出一条简单路径,但是找出来的不是最优路径.因此本文采用A ...

  3. 我的Windows核心编程——完成端口+套接字 图解

    ========================声明============================ 本文原创,转载请注明作者和出处,并保证文章的完整性(包括本声明). 本文不定期修改完善,为 ...

  4. jQuery Validate 表单验证插件----利用jquery.metadata.js将校验规则直接写在class属性里面并定义错误信息的提示

    一.下载依赖包 网盘下载:https://yunpan.cn/cryvgGGAQ3DSW  访问密码 f224 二. 添加一个另外一个插件jquery.metadata.js 并把校验规则写在控件里面 ...

  5. 2013年 蓝桥杯预赛 java 本科A 题目

    1.标题: 世纪末的星期 曾有邪教称1999年12月31日是世界末日.当然该谣言已经不攻自破. 还有人称今后的某个世纪末的12月31日,如果是星期一则会.... 有趣的是,任何一个世纪末的年份的12月 ...

  6. [转]highcharts图表入门之:如何让highcharts图表自适应浏览器窗体的大小或者页面大小

    本文转自: http://jsfiddle.net/vCZ8V/1/ http://www.stepday.com/topic/?740 http://blog.csdn.net/yueritian/ ...

  7. HDU 5056 Boring Count --统计

    题解见官方题解,我这里只实现一下,其实官方题解好像有一点问题诶,比如 while( str[startPos] != str[i+1] ) cnt[str[startPos]]--, startPos ...

  8. 权限框架 - shiro 授权demo

    之前说了权限认证,其实也就是登录验证身份 这次来说说shiro的授权 shiro可以针对角色授权,或者访问资源授权 两者都行,但是在如今的复杂系统中,当然使用后者,如果你是小系统或者私活的话,前者即可 ...

  9. centos6.5 redis3 开机自动启动命令设置

    修改redis.conf,打开后台运行选项: # By default Redis does not run as a daemon. Use 'yes' if you need it. # Note ...

  10. Android多线程----异步消息处理机制之Handler详解

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...