次の方法で共有


抽象クラス

抽象クラス は、一部またはすべてのメンバーを実装したままにするクラスであり、派生クラスから実装を提供できます。

構文

// 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

注釈

オブジェクト指向プログラミングでは、抽象クラスは階層の基底クラスとして使用され、多様なオブジェクト型のセットの共通機能を表します。 "abstract" という名前が示すように、抽象クラスは多くの場合、問題ドメイン内の具象エンティティに直接対応していません。 ただし、これらは、多くの異なる具象エンティティの共通点を表します。

抽象クラスには、 AbstractClass 属性が必要です。 実装されたメンバーと実装されていないメンバーを持つことができます。 クラスに適用する場合の 抽象 という用語の使用は、他の .NET 言語と同じです。ただし、メソッド (およびプロパティ) に適用する場合の 抽象 という用語の使用は、F# では他の .NET 言語での使用とは少し異なります。 F# では、メソッドが abstract キーワードでマークされている場合、これはメンバーがその型の仮想関数の内部テーブルに、 仮想ディスパッチ スロットと呼ばれるエントリを持っていることを示します。 つまり、 virtual キーワードは F# では使用されませんが、メソッドは仮想です。 キーワード abstract は、メソッドが実装されているかどうかに関係なく、仮想メソッドで使用されます。 仮想ディスパッチ スロットの宣言は、そのディスパッチ スロットのメソッドの定義とは別です。 したがって、別の .NET 言語での仮想メソッドの宣言と定義に相当する F# は、抽象メソッド宣言と個別の定義の両方を、 default キーワードまたは override キーワードと組み合わせたものです。 詳細と例については、「 メソッド」を参照してください。

クラスは、宣言されているが定義されていない抽象メソッドがある場合にのみ抽象と見なされます。 したがって、抽象メソッドを持つクラスは、必ずしも抽象クラスであるとは限りません。 クラスに未定義の抽象メソッドがない場合は、 AbstractClass 属性を使用しないでください。

前の構文では、 アクセシビリティ修飾子publicprivate 、または internalできます。 詳細については、「 アクセス制御」を参照してください。

他の型と同様に、抽象クラスは基底クラスと 1 つ以上の基本インターフェイスを持つことができます。 各基底クラスまたはインターフェイスは、 inherit キーワードと共に個別の行に表示されます。

抽象クラスの型定義には、完全に定義されたメンバーを含めることができますが、抽象メンバーを含めることもできます。 抽象メンバーの構文は、前の構文で個別に示されています。 この構文では、メンバーの 型シグネチャ は、パラメーター型を順番に含むリストであり、戻り値の型は、 -> トークンまたは * トークンで区切られ、カリー化されたパラメーターと組み合わせたパラメーターに適しています。 抽象メンバー型シグネチャの構文は、署名ファイルで使用される構文と同じで、Visual Studio Code エディターの IntelliSense で表示される構文と同じです。

次のコードは、2 つの非抽象派生クラスである Square と Circle を持つ抽象クラス Shape を示しています。 この例では、抽象クラス、メソッド、およびプロパティを使用する方法を示します。 この例では、抽象クラス Shape は、コンクリート エンティティの円と正方形の共通要素を表しています。 (2 次元座標系内の) すべての図形の共通の特徴は、グリッド上の位置、回転角度、面積と境界のプロパティなど、Shape クラスに抽象化されます。 これらは、位置を除き、個々の図形を変更できない動作をオーバーライドできます。

回転メソッドは、Circle クラスのようにオーバーライドできます。これは、対称性のために回転不変です。 したがって、Circle クラスでは、rotation メソッドは何もしないメソッドに置き換えられます。

// 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

こちらも参照ください