F# - 繼承



面向物件程式設計中最重要的概念之一是繼承。繼承允許我們根據另一個類來定義一個類,這使得建立和維護應用程式變得更容易。這也提供了重用程式碼功能和加快實現時間的機會。

在建立類時,程式設計師可以指定新類應該繼承現有類的成員,而不是完全編寫新的資料成員和成員函式。這個現有的類稱為基類,新類稱為派生類。

繼承的概念實現了 IS-A 關係。例如,哺乳動物 IS A 動物,狗 IS-A 哺乳動物,因此狗 IS-A 動物,依此類推。

基類和子類

子類派生自已定義的基類。子類繼承基類的成員,並擁有自己的成員。

子類使用inherit關鍵字定義,如下所示:

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

在 F# 中,一個類最多隻能有一個直接基類。如果未使用inherit關鍵字指定基類,則該類隱式地繼承自 Object。

請注意:

  • 基類的的方法和成員對派生類的使用者可用,就像派生類的直接成員一樣。

  • let 繫結和建構函式引數對類是私有的,因此無法從派生類訪問。

  • 關鍵字base指的是基類例項。它像 self 識別符號一樣使用。

示例

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# 中的方法不可重寫。

要在派生類中重寫方法,必須使用abstractdefault關鍵字將方法宣告為可重寫,如下所示:

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.
廣告

© . All rights reserved.