abstract
abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。
抽象类具有以下特性:
抽象方法具有以下特性:
除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。
virtaul
virtaul 关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写(为了被重写abstract 及virtaul 都不能是私有的)
调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。
默认情况下,方法是非虚拟的。不能重写非虚方法。
virtual 修饰符不能与 static、abstract, private 或 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 关键字放置在要替换的类成员的返回类型之前。以下代码提供了一个示例:
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 关键字的前面。例如:
多态 (上面的都是铺垫)
多态性常被视为自封装和继承之后,面向对象的编程的第三个支柱。
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("这是另一个新的方法");
}
}
}