abstract virtaul override new 及多态

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 关键字放置在要替换的类成员的返回类型之前。以下代码提供了一个示例:

C#

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; }
    }
}

通过将派生类的实例强制转换为基类的实例,仍然可以从客户端代码访问隐藏的基类成员。例如:

C#

DerivedClass B = new DerivedClass();
B.DoWork();  // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork();  // Calls the old method.

从派生类访问基类虚拟成员

已替换或重写某个方法或属性的派生类仍然可以使用基关键字访问基类的该方法或属性。 以下代码提供了一个示例:

C#

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[0].Do();
    
                Dos[1].Do();
    
                Console.ReadKey();
    
                List<DoMyWork> MyDos = new List<DoMyWork>();
    
                MyDos.Add(new MyDo1());
    
                MyDos.Add(new MyDo2());
    
                MyDos.Add(new MyDo3());
    
                MyDos[0].Do();
    
                MyDos[1].Do();
    
                MyDos[2].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("这是另一个新的方法");
    
            }
    
        }
    
    }
时间: 2024-10-28 18:41:10

abstract virtaul override new 及多态的相关文章

sealed、new、virtual、abstract与override 总结

原文地址:http://www.cnblogs.com/DebugLZQ/archive/2011/08/09/2132468.html 1. sealed--"断子绝孙" 密封类不能被继承.密封方法可以重写基类中的方法,但其本身不能在任何派生类中进一步重写.当应用于方法或属性时,sealed修饰符必须始终与override一起使用. 即:密封类不会有子类,所以是"断子绝孙". 2. new--"你是我的,我是我的" new关键字用于显式隐藏从基

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

原文地址:http://blog.csdn.net/richerg85/article/details/7407544 abstract      修饰类名为抽象类,修饰方法为抽象方法.如果一个类为抽象类,则这个类智能是其他某个类的基类.抽象方法在抽象类中没有函数体.抽象类中的抽象方法是没有方法体的,继承其的子类必须实现抽象类的抽象方法. 抽象类有如下特征: 抽象类不能实例化 抽象类的派生类必须实现所有抽象方法 抽象类中的抽象方法是没有方法体的,继承其的子类必须实现抽象类的抽象方法 抽象方法:

sealed、new、virtual、abstract与override 趣解(6)

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 1. sealed--"断子绝孙"    

abstract,virtual,override个人

1.abstract 可以修饰类和方法,修饰方法时只声明不实现: 2.继承实现abstract类必须通过override实现abstract声明的方法,而virtual方法可选择override(重写)实现: 3.

abstract,virtual,override

1.abstract 可以修饰类和方法,修饰方法时只声明不实现: 2.继承实现abstract类必须通过override实现abstract声明的方法,而virtual方法可选择override(重写)实现: 3.

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

virtual是把一个方法声明为虚方法,使派生类可重写此方法,一般建立的方法是不能够重写的,譬如类A中有个方法protected void method(){ 原代码....;}类B继承自类A,类B能够调用类A的method()方法,但不能更改方法体代码,但当类A中使用了virtual声明此方法: protected virtual void method(),那么类B可通过使用override重写此方法protected override void method(){ 新代码....;}vir

c#中抽象类,interface,abstract、override、virtual、sealed使用

interface:接口声明不包括数据成员,只能包含方法,属性,事件,索引等成员,使用接口时不能声明抽象成员(不能直接new实例化) public interface IStringList //接口一般用I作为首字母 { //接口声明不包括数据成员,只能包含方法.属性.事件.索引等成员 //使用接口时不能声明抽象成员(不能直接new实例化) void Add ( string s ) ; int Count{ get; } string this[int index] { get; set;

C#基础知识(base、this、new、override、abstract、virtual、static)

前言 本文主要来讲解一下C#中,自己觉得掌握的不怎么样或者用的不多,不太熟悉的关键字,主要包括base.this.new.override.abstract.virtual以及针对static字段和static构造函数之间的执行问题. base关键字 base 关键字用于在派生类中实现对基类公有或者受保护成员的访问,但是只局限在构造函数.实例方法和实例属性访问器中: 调用基类上已被其他方法重写的方法. public class Father { public virtual void Say()

快学Scala 第十九课 (trait的abstract override使用)

trait的abstract override使用: 当我看到abstract override介绍的时候也是一脸懵逼,因为快学scala,只介绍了因为TimestampLogger中调用的super.log依旧是个abstract class,所以必须在方法前加上abstract和override.但是并没有具体介绍如何使用,然后查阅了其他文档,才明白使用方法. 下面的代码定义了超类LoggerEmpty,这个定义意味着该特质只能混入扩展LoggerEmpty的类中. 在特质中声明抽象方法中有