Fsharp-inheritance

提供:Dev Guides
移動先:案内検索

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.