抽象類別

抽象類別,這種類別不見得會實作出所有或部分成員,而是留待衍生類別各自提供實作。

語法

// 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 關鍵字一起出現在個別行上。

抽象類別的型別定義可以包含完整定義的成員,但是也可以包含抽象成員。 抽象成員的語法在先前的語法中個別顯示。 在此語法中,成員的 型別特徵標記 是一份清單,其中包含按照順序的參數型別和傳回型別,並依適用於局部調用和元組參數的 -> 標記和/或 * 標記分隔。 抽象成員型別特徵標記的語法與特徵標記檔案中使用的語法,以及由 IntelliSense 在 [Visual Studio Code 編輯器] 中顯示的語法相同。

下列程式碼說明抽象類別 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

另請參閱