継承

継承は、オブジェクト指向プログラミングで "is-a" 関係 (サブタイプ) をモデル化するために使用されます。

継承関係の指定

継承関係を指定するには、クラス宣言で inherit キーワードを使用します。 次の例に基本的な構文形式を示します。

type MyDerived(...) =
    inherit MyBase(...)

派生クラスには、直接基底クラスを 1 つだけ指定できます。 inherit キーワードを使用して基底クラスを指定しない場合、そのクラスでは System.Object から暗黙的に継承します。

継承メンバー

クラスが別のクラスから継承される場合、派生クラスのユーザーは、その基底クラスのメソッドとメンバーを、その派生クラスの直接のメンバーであるかのように使用できます。

すべての let バインディングとコンストラクターのパラメーターはクラスに対してプライベートであるため、派生クラスからアクセスすることはできません。

キーワード base は派生クラスで使用可能で、基底クラスのインスタンスが参照されます。 これは、自己識別子のように使用されます。

仮想メソッドとオーバーライド

仮想メソッド (およびプロパティ) は、他の .NET 言語と比較して、F# では多少異なる動作をします。 新しい仮想メンバーを宣言するには、abstract キーワードを使用します。 これは、そのメソッドの既定の実装を提供するかどうかに関係なく行います。 したがって、基底クラスの仮想メソッドの完全な定義は、このパターンに従います。

abstract member [method-name] : [type]

default [self-identifier].[method-name] [argument-list] = [method-body]

そして派生クラスでは、この仮想メソッドのオーバーライドはこのパターンに従います。

override [self-identifier].[method-name] [argument-list] = [method-body]

基底クラスで既定の実装を省略した場合、その基底クラスは抽象クラスになります。

次のコード例に、基底クラスでの新しい仮想メソッド function1 の宣言と、派生クラスでそれをオーバーライドする方法を示します。

type MyClassBase1() =
    let mutable z = 0
    abstract member function1: int -> int

    default u.function1(a: int) =
        z <- z + a
        z

type MyClassDerived1() =
    inherit MyClassBase1()
    override u.function1(a: int) = a + 1

コンストラクターと継承

基底クラスのコンストラクターは、派生クラスで呼び出す必要があります。 基底クラスのコンストラクターの引数は、inherit 句の引数リストに表示されます。 使用される値は、派生クラスのコンストラクターに渡される引数から決定される必要があります。

次のコードは、基底クラスと派生クラスを示しています。派生クラスの inherit 句から基底クラスのコンストラクターが呼び出されます。

type MyClassBase2(x: int) =
    let mutable z = x * x

    do
        for i in 1..z do
            printf "%d " i


type MyClassDerived2(y: int) =
    inherit MyClassBase2(y * 2)

    do
        for i in 1..y do
            printf "%d " i

複数のコンストラクターの場合は、次のコードを使用できます。 派生クラスのコンストラクターの最初の行は inherit 句で、フィールドは val キーワードで宣言された明示的なフィールドとして表示されます。 詳細については、「明示的なフィールド: val キーワード」を参照してください。

type BaseClass =
    val string1 : string
    new (str) = { string1 = str }
    new () = { string1 = "" }

type DerivedClass =
    inherit BaseClass

    val string2 : string
    new (str1, str2) = { inherit BaseClass(str1); string2 = str2 }
    new (str2) = { inherit BaseClass(); string2 = str2 }

let obj1 = DerivedClass("A", "B")
let obj2 = DerivedClass("A")

継承の代替手段

型を少し変更する必要がある場合は、継承の代わりにオブジェクト式を使用することを検討してください。 次の例は、新しい派生型を作成する代わりに、オブジェクト式を使用する方法を示しています。

open System

let object1 =
    { new Object() with
        override this.ToString() = "This overrides object.ToString()" }

printfn "%s" (object1.ToString())

オブジェクト式の詳細については、「オブジェクト式」を参照してください。

オブジェクト階層を作成する場合は、継承の代わりに判別共用体を使用することを検討してください。 判別共用体では、共通する型全般を共有する各種オブジェクトのさまざまな動作をモデル化することもできます。 単一の判別共用体を使用すると、多くの場合に、互いにわずかな違いしかない多数の派生クラスが不要になります。 判別共用体の詳細については、「判別共用体」を参照してください。

関連項目