Наследование

Наследование используется для моделирования связи «является-a» или подтипов в объектно-ориентированном программировании.

Указание отношений наследования

Отношения наследования указываются с помощью inherit ключевого слова в объявлении класса. В следующем примере показана базовая синтаксическая форма.

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

Класс может иметь не более одного прямого базового класса. Если базовый класс не указан с помощью inherit ключевого слова, класс неявно наследует от System.Object .

Унаследованные элементы

Если класс наследуется от другого класса, методы и члены базового класса становятся доступными для пользователей производного класса, как если бы они были прямыми членами производного класса.

Все привязки let и параметры конструктора являются закрытыми для класса, поэтому к ним нельзя получить доступ из производных классов.

Ключевое слово base доступно в производных классах и ссылается на экземпляр базового класса. Он используется как идентификатор Self.

Виртуальные методы и переопределения

Виртуальные методы (и свойства) работают несколько иначе в F # по сравнению с другими языками .NET. Для объявления нового виртуального члена используется 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())

Дополнительные сведения о выражениях объектов см. в разделе выражения объекта.

При создании иерархий объектов рассмотрите возможность использования размеченного объединения вместо наследования. Размеченные объединения могут также моделировать поведение различных объектов, совместно использующих общий тип. Одно размеченное объединение часто может устранить необходимость в ряде производных классов, которые являются незначительными вариантами друг друга. Сведения о размеченных объединениях см. в разделе Размеченные объединения.

См. также