抽象类

抽象类是使部分成员或全部成员未实现的类,以便可以由派生类来提供实现。

语法

// Abstract class syntax.
[<AbstractClass>]
type [ accessibility-modifier ] abstract-class-name =
[ inherit base-class-or-interface-name ]
[ abstract-member-declarations-and-member-definitions ]

// Abstract member syntax.
abstract member member-name : type-signature

备注

在面向对象的编程中,抽象类用作层次结构的基类,并表示一组不同的对象类型的常用功能。 如名称“抽象”所示,抽象类通常不直接与问题域中的具体实体对应。 不过,它们确实代表许多不同的具体实体的共同点。

抽象类必须具有 AbstractClass 属性。 它们可以拥有已实现的和未实现的成员。 当应用于类时,“抽象”一词的用法与其他 .NET 语言相同;但当应用于方法(和属性)时,“抽象”一词在 F# 中的用法与它在其他 .NET 语言中的用法稍有不同。 在 F# 中,使用 abstract 关键字标记方法时,这表示成员在该类型的虚函数的内部表中有一个称为“虚拟调度槽”的项。 换句话说,方法为虚方法,但 F# 中未使用 virtual 关键字。 关键字 abstract 用于虚方法,无论该方法是否已实现。 虚拟调度槽的声明与该调度槽的方法定义是独立的。 因此,与其他 .NET 语言中的虚方法声明和定义等效的 F# 等效项是使用 default 关键字或 override 关键字的抽象方法声明和单独定义的组合。 有关详细信息和示例,请参阅方法

仅当存在已声明但未定义的抽象方法时,才将类视为抽象类。 因此,具有抽象方法的类不一定是抽象类。 请勿使用 AbstractClass 属性,除非类具有未定义的抽象方法。

在前面的语法中,可访问性修饰符可以是 publicprivateinternal。 有关详细信息,请参阅访问控制

与其他类型一样,抽象类可以具有一个基类以及一个或多个基接口。 每个基类或基接口都显示在单独的行中,并带有 inherit 关键字。

抽象类的类型定义可包含完全定义的成员,但也可以包含抽象成员。 在前面的语法中,抽象成员的语法是单独显示的。 在此语法中,成员的类型签名是一个列表,其中包含按顺序排列的参数类型和返回类型(由适用于扩充参数和元组参数的 -> 标记和/或 * 标记分隔)。 抽象成员类型签名的语法与签名文件中使用的语法以及 Visual Studio Code 编辑器中由 IntelliSense 显示的语法相同。

下面的代码阐释一个抽象类 Shape,它具有两个非抽象的派生类(即 Square 和 Circle)。 该示例演示如何使用抽象类、方法和属性。 在此示例中,抽象类 Shape 表示两个具体实体(圆和方形)的通用元素。 所有形状的通用特征(在二维坐标系中)均被提取到 Shape 类中:在网格中的位置、旋转角度以及区域和外围属性。 可以重写这些特征(位置除外),不能更改各个形状的行为。

可以重写旋转方法,就像在 Circle 类中一样,因为它是对称的,所以具有旋转不变性。 因此在 Circle 类中,旋转方法替换为不执行任何操作的方法。

// An abstract class that has some methods and properties defined
// and some left abstract.
[<AbstractClass>]
type Shape2D(x0: float, y0: float) =
    let mutable x, y = x0, y0
    let mutable rotAngle = 0.0

    // These properties are not declared abstract. They
    // cannot be overriden.
    member this.CenterX
        with get () = x
        and set xval = x <- xval

    member this.CenterY
        with get () = y
        and set yval = y <- yval

    // These properties are abstract, and no default implementation
    // is provided. Non-abstract derived classes must implement these.
    abstract Area: float with get
    abstract Perimeter: float with get
    abstract Name: string with get

    // This method is not declared abstract. It cannot be
    // overridden.
    member this.Move dx dy =
        x <- x + dx
        y <- y + dy

    // An abstract method that is given a default implementation
    // is equivalent to a virtual method in other .NET languages.
    // Rotate changes the internal angle of rotation of the square.
    // Angle is assumed to be in degrees.
    abstract member Rotate: float -> unit
    default this.Rotate(angle) = rotAngle <- rotAngle + angle

type Square(x, y, sideLengthIn) =
    inherit Shape2D(x, y)
    member this.SideLength = sideLengthIn
    override this.Area = this.SideLength * this.SideLength
    override this.Perimeter = this.SideLength * 4.
    override this.Name = "Square"

type Circle(x, y, radius) =
    inherit Shape2D(x, y)
    let PI = 3.141592654
    member this.Radius = radius
    override this.Area = PI * this.Radius * this.Radius
    override this.Perimeter = 2. * PI * this.Radius
    // Rotating a circle does nothing, so use the wildcard
    // character to discard the unused argument and
    // evaluate to unit.
    override this.Rotate(_) = ()
    override this.Name = "Circle"

let square1 = new Square(0.0, 0.0, 10.0)
let circle1 = new Circle(0.0, 0.0, 5.0)
circle1.CenterX <- 1.0
circle1.CenterY <- -2.0
square1.Move -1.0 2.0
square1.Rotate 45.0
circle1.Rotate 45.0
printfn "Perimeter of square with side length %f is %f, %f" (square1.SideLength) (square1.Area) (square1.Perimeter)
printfn "Circumference of circle with radius %f is %f, %f" (circle1.Radius) (circle1.Area) (circle1.Perimeter)

let shapeList: list<Shape2D> = [ (square1 :> Shape2D); (circle1 :> Shape2D) ]
List.iter (fun (elem: Shape2D) -> printfn "Area of %s: %f" (elem.Name) (elem.Area)) shapeList

输出:

Perimeter of square with side length 10.000000 is 40.000000
Circumference of circle with radius 5.000000 is 31.415927
Area of Square: 100.000000
Area of Circle: 78.539816

请参阅