C#中的Virtual、Override和new关键词

2008-06-16 15:25:44.0     浏览:1220     来源:e800.net频道
关键词:  C#     Virtual     Override     new     ID  

摘要:C#是继C++Java语言后的又一面向对象的语言,在语法结构,C#有很多地方和C++Java相似,但是又不同于它们,其中一些关键特别需要引起我们的注意。

virtual 关键字用于修改方法或属性的声明,在这种情况下,方法或属性被称作虚拟成员。虚拟成员的实现可由派生类中的重写成员更改。

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

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

不能将 virtual 修饰符与以下修饰符一起使用:

static abstract override

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

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

上边是微软的官方说明,个人认为,如果自己觉得这个方法通用性不强就用virtual去声明这个方法,然后用户可以根据自己不同的情况首先继承它然后对它进行重载。下面我们来看一下微软给的例子:

示例

在该示例中,Dimensions 类包含 x y 两个坐标和 Area() 虚方法。不同的形状类,如 CircleCylinder Sphere 继承 Dimensions 类,并为每个图形计算表面积。每个派生类都有各自的 Area() 重写实现。根据与此方法关联的对象,通过调用正确的 Area() 实现,该程序为每个图形计算并显示正确的面积。

1 // cs_virtual_keyword.cs
2 // Virtual and override
3 using System;
4 class TestClass
5 {
6 public class Dimensions
7 {
8 public const double pi = Math.PI;
9 protected double x, y;
10 public Dimensions()
11 {
12 }
13 public Dimensions (double x, double y)
14 {
15 this.x = x;
16 this.y = y;
17 }
18
19 public virtual double Area()
20 {
21 return x*y;
22 }
23 }
24
25 public class Circle: Dimensions
26 {
27 public Circle(double r): base(r, 0)
28 {
29 }
30
31 public override double Area()
32 {
33 return pi * x * x;
34 }
35 }
36
37 class Sphere: Dimensions
38 {
39 public Sphere(double r): base(r, 0)
40 {
41 }
42
43 public override double Area()
44 {
45 return 4 * pi * x * x;
46 }
47 }
48
49 class Cylinder: Dimensions
50 {
51 public Cylinder(double r, double h): base(r, h)
52 {
53 }
54
55 public override double Area()
56 {
57 return 2*pi*x*x + 2*pi*x*y;
58 }
59 }
60
61 public static void Main()
62 {
63 double r = 3.0, h = 5.0;
64 Dimensions c = new Circle(r);
65 Dimensions s = new Sphere(r);
66 Dimensions l = new Cylinder(r, h);
67 // Display results:
68 Console.WriteLine("Area of Circle = {0:F2}", c.Area());
69 Console.WriteLine("Area of Sphere = {0:F2}", s.Area());
70 Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());
71 }
72 }

输出

Area of Circle = 28.27

Area of Sphere = 113.10

Area of Cylinder = 150.80

在前面的示例中,注意继承的类 CircleSphere Cylinder 都使用了初始化基类的构造函数,例如:

public Cylinder(double r, double h): base(r, h) {}

其中关键字override表示派生类重写基虚方法,也可以使用关键字newnew表示隐藏基类中的虚方法。如果 override 关键字和 new 关键字均未指定,编译器将发出警告,并且派生类中的方法将隐藏基类中的方法。

下面我们通过微软的一个例子,来一下了解何时使用 Override New 关键字。

首先声明三个类:一个名为 Car 的基类以及从该基类派生的两个类 ConvertibleCar Minivan。基类包含一个可将有关汽车的描述发送到控制台的方法 (DescribeCar)。派生类方法也包含一个名为 DescribeCar 的方法,该方法显示派生类的独特属性。这些方法还调用基类的 DescribeCar 方法来演示从 Car 类继承属性的方式。

为了强调区别,ConvertibleCar 类使用 new 关键字来定义,而 Minivan 类使用 override 来定义。

现在可以编写一些代码来声明这些类的实例,并调用它们的方法以便对象能够描述其自身:

正如预期的那样,输出类似如下所示:

Four wheels and an engine.

----------

Four wheels and an engine.

A roof that opens up.

----------

Four wheels and an engine.

Carries seven people.

----------

但是,在该代码接下来的一节中,我们声明了一个从 Car 基类派生的对象的数组。此数组能够存储 CarConvertibleCar Minivan 对象。该数组的声明类似如下所示:

然后可以使用一个 foreach 循环来访问该数组中包含的每个 Car 对象,并调用 DescribeCar 方法,如下所示:

此循环的输出如下所示:

Car object: YourApplication.Car

Four wheels and an engine.

----------

Car object: YourApplication.ConvertibleCar

Four wheels and an engine.

----------

Car object: YourApplication.Minivan

Four wheels and an engine.

Carries seven people.

----------

注意,ConvertibleCar 说明与您的预期不同。由于使用了 new 关键字来定义此方法,所调用的不是派生类方法,而是基类方法。Minivan 对象正确地调用重写方法,并产生预期的结果。

若要强制一个规则,要求从 Car 派生的所有类都必须实现 DescribeCar 方法,则应创建一个新的基类,将方法 DescribeCar 定义为 abstract。抽象方法不包含任何代码,仅包含方法签名。从此基类派生的任何类都必须提供 DescribeCar 的实现。