Fsharp-inheritance
F#-継承
オブジェクト指向プログラミングで最も重要な概念の1つは、継承の概念です。 継承を使用すると、クラスを別のクラスの観点から定義でき、アプリケーションの作成と保守が簡単になります。 これにより、コード機能を再利用して実装時間を短縮することもできます。
クラスを作成するとき、プログラマは完全に新しいデータメンバーとメンバー関数を記述する代わりに、新しいクラスが既存のクラスのメンバーを継承するように指定できます。 この既存のクラスは基本クラスと呼ばれ、新しいクラスは派生クラスと呼ばれます。
継承の概念は、IS-A関係を実装します。 たとえば、哺乳類は動物、犬はIS-A哺乳類、したがって犬はIS-A動物などです。
基本クラスとサブクラス
サブクラスは、すでに定義されている基本クラスから派生します。 サブクラスは、基本クラスのメンバーを継承し、独自のメンバーを持っています。
サブクラスは、以下に示すように inherit キーワードを使用して定義されます-
type MyDerived(...) =
inherit MyBase(...)
F#では、クラスは最大で1つの直接ベースクラスを持つことができます。 inherit キーワードを使用して基本クラスを指定しない場合、クラスは暗黙的にObjectを継承します。
注意してください-
- 基本クラスのメソッドとメンバーは、派生クラスの直接メンバーのように、派生クラスのユーザーが利用できます。
- バインディングとコンストラクターのパラメーターはクラスに対してプライベートであるため、派生クラスからはアクセスできません。
- キーワード base は、基本クラスのインスタンスを指します。 自己識別子のように使用されます。
例
type Person(name) =
member x.Name = name
member x.Greet() = printfn "Hi, I'm %s" x.Name
type Student(name, studentID : int) =
inherit Person(name)
let mutable _GPA = 0.0
member x.StudentID = studentID
member x.GPA
with get() = _GPA
and set value = _GPA <- value
type Teacher(name, expertise : string) =
inherit Person(name)
let mutable _salary = 0.0
member x.Salary
with get() = _salary
and set value = _salary <- value
member x.Expertise = expertise
//using the subclasses
let p = new Person("Mohan")
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")
p.Greet()
st.Greet()
tr.Greet()
あなたがプログラムをコンパイルして実行すると、次の出力が得られます-
Hi, I'm Mohan
Hi, I'm Zara
Hi, I'm Mariam
メソッドのオーバーライド
基本クラスメソッドのデフォルトの動作をオーバーライドし、サブクラスまたは派生クラスで異なる方法で実装できます。
F#のメソッドは、デフォルトではオーバーライドできません。
派生クラスのメソッドをオーバーライドするには、次のように abstract および default キーワードを使用してメソッドをオーバーライド可能として宣言する必要があります-
type Person(name) =
member x.Name = name
abstract Greet : unit -> unit
default x.Greet() = printfn "Hi, I'm %s" x.Name
これで、Personクラスの_Greet_メソッドを派生クラスでオーバーライドできます。 次の例はこれを示しています-
例
type Person(name) =
member x.Name = name
abstract Greet : unit -> unit
default x.Greet() = printfn "Hi, I'm %s" x.Name
type Student(name, studentID : int) =
inherit Person(name)
let mutable _GPA = 0.0
member x.StudentID = studentID
member x.GPA
with get() = _GPA
and set value = _GPA <- value
override x.Greet() = printfn "Student %s" x.Name
type Teacher(name, expertise : string) =
inherit Person(name)
let mutable _salary = 0.0
member x.Salary
with get() = _salary
and set value = _salary <- value
member x.Expertise = expertise
override x.Greet() = printfn "Teacher %s." x.Name
//using the subclasses
let p = new Person("Mohan")
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")
//default Greet
p.Greet()
//Overriden Greet
st.Greet()
tr.Greet()
あなたがプログラムをコンパイルして実行すると、次の出力が得られます-
Hi, I'm Mohan
Student Zara
Teacher Mariam.
抽象クラス
オブジェクトの不完全な実装を提供する必要がある場合がありますが、実際には実装すべきではありません。 後で、他のプログラマーが抽象クラスのサブクラスを作成して完全な実装にする必要があります。
たとえば、学校管理システムではPersonクラスは必要ありません。 ただし、StudentクラスまたはTeacherクラスが必要になります。 このような場合、Personクラスを抽象クラスとして宣言できます。
*AbstractClass* 属性は、クラスにいくつかの抽象メンバーがあることをコンパイラーに伝えます。
クラスが完全に実装されていないため、抽象クラスのインスタンスを作成することはできません。
次の例はこれを示しています-
例
[<AbstractClass>]
type Person(name) =
member x.Name = name
abstract Greet : unit -> unit
type Student(name, studentID : int) =
inherit Person(name)
let mutable _GPA = 0.0
member x.StudentID = studentID
member x.GPA
with get() = _GPA
and set value = _GPA <- value
override x.Greet() = printfn "Student %s" x.Name
type Teacher(name, expertise : string) =
inherit Person(name)
let mutable _salary = 0.0
member x.Salary
with get() = _salary
and set value = _salary <- value
member x.Expertise = expertise
override x.Greet() = printfn "Teacher %s." x.Name
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")
//Overriden Greet
st.Greet()
tr.Greet()
あなたがプログラムをコンパイルして実行すると、次の出力が得られます-
Student Zara
Teacher Mariam.