【abstract】
abstract
修饰符指示所修饰的内容缺少实现或未完全实现。 abstract 修饰符可用于类、方法、属性、索引器和事件。 在类声明中使用 abstract
修饰符以指示某个类只能是其他类的基类。 标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。
示例:
在此例中,类 Square
必须提供 Area
的实现,因为它派生自 ShapesClass
abstract class ShapesClass { abstract public int Area();} class Square : ShapesClass { int side = 0; public Square(int n) { side = n; } // Area method is required to avoid // a compile-time error. public override int Area() { return side * side; } static void Main() { Square sq = new Square(12); Console.WriteLine("Area of the square = {0}", sq.Area()); } interface I { void M(); } abstract class C : I { public abstract void M(); } } // Output: Area of the square = 144
抽象类具有以下特性:
- 抽象类不能实例化。
- 抽象类可以包含抽象方法和抽象访问器。
- 不能用 sealed 修饰符修饰抽象类,因为这两个修饰符的含义是相反的。 采用
sealed
修饰符的类无法继承,而abstract
修饰符要求对类进行继承。 - 从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实际实现。
在方法或属性声明中使用 abstract
修饰符以指示方法或属性不包含实现。
抽象方法具有以下特性:
- 抽象方法是隐式的虚方法。
- 只允许在抽象类中使用抽象方法声明。
- 因为抽象方法声明不提供实际的实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号 ({ })。 例如:
public abstract void MyMethod();
实现由一个重写方法重写提供,此重写方法是非抽象类的一个成员。
- 在抽象方法声明中使用 static 或 virtual 修饰符是错误的。除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。
- 在静态属性上使用
abstract
修饰符是错误的。 - 在派生类中,通过包括使用 override 修饰符的属性声明,可以重写抽象的继承属性。
- 实现接口的抽象类可以将接口方法映射到抽象方法上。 例如:
interface I { void M(); } abstract class C : I { public abstract void M(); }
示例:
在本例中,DerivedClass
类是从抽象类 BaseClass
派生的。 抽象类包含一个抽象方法 AbstractMethod
和两个抽象属性 X
和 Y
。
abstract class BaseClass // Abstract class { protected int _x = 100; protected int _y = 150; public abstract void AbstractMethod(); // Abstract method public abstract int X { get; } public abstract int Y { get; } } class DerivedClass : BaseClass { public override void AbstractMethod() { _x++; _y++; } public override int X // overriding property { get { return _x + 10; } } public override int Y // overriding property { get { return _y + 10; } } static void Main() { DerivedClass o = new DerivedClass(); o.AbstractMethod(); Console.WriteLine("x = {0}, y = {1}", o.X, o.Y); } } // Output: x = 111, y = 161
在上面的示例中,如果尝试通过使用下面的语句将抽象类实例化:
BaseClass bc = new BaseClass(); // Error
将出现错误,指出编译器无法创建抽象类“BaseClass”的实例。
【virtual】
virtual
关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写。 例如,此方法可被任何继承它的类重写。
public virtual double Area() { return x * y; }
调用虚方法时,将为重写成员检查该对象的运行时类型。 将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。
默认情况下,方法是非虚拟的。 不能重写非虚方法。
virtual
修饰符不能与 static
、abstract, private
或 override
修饰符一起使用。 下面的示例演示一个虚拟属性:
class MyBaseClass { // virtual auto-implemented property. Overrides can only // provide specialized behavior if they implement get and set accessors. public virtual string Name { get; set; } // ordinary virtual property with backing field private int num; public virtual int Number { get { return num; } set { num = value; } } } class MyDerivedClass : MyBaseClass { private string name; // Override auto-implemented property with ordinary property // to provide specialized accessor behavior. public override string Name { get { return name; } set { if (value != String.Empty) { name = value; } else { name = "Unknown"; } } } }
除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。
- 在静态属性上使用
virtual
修饰符是错误的。 - 通过包括使用
override
修饰符的属性声明,可在派生类中重写虚拟继承属性。
示例:
在该示例中,Shape
类包含 x
、y
两个坐标和 Area()
虚方法。 不同的形状类,如 Circle
、Cylinder
和 Sphere
继承 Shape
类,并为每个图形计算表面积。 每个派生类都有各自的 Area()
重写实现。
通知继承的类 Circle
、 Sphere
和 Cylinder
初始化基类的所有使用构造函数,如以下声明所示。
public Cylinder(double r, double h): base(r, h) {}
下面的过程通过调用 Area()
方法的适当实现计算并显示由每个图形的合适区域,根据与该方法的对象。
class TestClass { public class Shape { public const double PI = Math.PI; protected double x, y; public Shape() { } public Shape(double x, double y) { this.x = x; this.y = y; } public virtual double Area() { return x * y; } } public class Circle : Shape { public Circle(double r) : base(r, 0) { } public override double Area() { return PI * x * x; } } class Sphere : Shape { public Sphere(double r) : base(r, 0) { } public override double Area() { return 4 * PI * x * x; } } class Cylinder : Shape { public Cylinder(double r, double h) : base(r, h) { } public override double Area() { return 2 * PI * x * x + 2 * PI * x * y; } } static void Main() { double r = 3.0, h = 5.0; Shape c = new Circle(r); Shape s = new Sphere(r); Shape l = new Cylinder(r, h); // Display results: Console.WriteLine("Area of Circle = {0:F2}", c.Area()); Console.WriteLine("Area of Sphere = {0:F2}", s.Area()); Console.WriteLine("Area of Cylinder = {0:F2}", l.Area()); } } /* Output: Area of Circle = 28.27 Area of Sphere = 113.10 Area of Cylinder = 150.80 */