Sdílet prostřednictvím


Abstraktní třídy

Abstraktní třídy jsou třídy , které opouštějí některé nebo všechny členy bez implementace, aby implementace mohly být poskytovány odvozenými třídami.

Syntaxe

// Abstract class syntax.
[<AbstractClass>]
type [ accessibility-modifier ] abstract-class-name =
[ inherit base-class-or-interface-name ]
[ abstract-member-declarations-and-member-definitions ]

// Abstract member syntax.
abstract member member-name : type-signature

Poznámky

V objektově orientovaném programování se abstraktní třída používá jako základní třída hierarchie a představuje společné funkce různorodé sady typů objektů. Jak už název "abstraktní" znamená, abstraktní třídy často neodpovídají přímo konkrétním entitám v problémové doméně. Představují však, co mnoho různých konkrétních entit má společné.

Abstraktní třídy musí mít AbstractClass atribut. Můžou mít implementované a neplementované členy. Použití termínu abstrakce při použití na třídu je stejné jako v jiných jazycích .NET. Použití termínu abstrakce při použití metod (a vlastností) se v jazyce F# od použití v jiných jazycích .NET trochu liší. Pokud je v jazyce F# metoda označená klíčovým slovem abstract , znamená to, že člen má položku, která se označuje jako virtuální slot dispečera, v interní tabulce virtuálních funkcí pro daný typ. Jinými slovy, metoda je virtuální, i když virtual se klíčové slovo nepoužívá v jazyce F#. Klíčové slovo abstract se používá u virtuálních metod bez ohledu na to, jestli je metoda implementována. Deklarace virtuálního dispečinkového slotu je oddělená od definice metody pro tento slot odeslání. Proto je ekvivalent jazyka F# deklarace a definice virtuální metody v jiném jazyce .NET kombinací abstraktní deklarace metody i samostatné definice s klíčovým slovem default nebo klíčovým slovem override . Další informace a příklady naleznete v tématu Metody.

Třída je považována za abstraktní pouze v případě, že existují abstraktní metody, které jsou deklarovány, ale nejsou definovány. Třídy, které mají abstraktní metody, nejsou nutně abstraktní třídy. Pokud třída nemá nedefinované abstraktní metody, nepoužívejte atribut AbstractClass .

V předchozí syntaxi může být publicmodifikátor přístupnosti , private nebo internal. Další informace najdete v článku Access Control.

Stejně jako u jiných typů mohou abstraktní třídy mít základní třídu a jedno nebo více základních rozhraní. Každá základní třída nebo rozhraní se zobrazí na samostatném řádku společně s klíčovým slovem inherit .

Definice typu abstraktní třídy může obsahovat plně definované členy, ale může také obsahovat abstraktní členy. Syntaxe abstraktních členů se zobrazuje samostatně v předchozí syntaxi. V této syntaxi je podpis typu člena seznam, který obsahuje typy parametrů v pořadí a návratové typy oddělené -> tokeny a/nebo * tokeny podle potřeby pro curried a řazené parametry. Syntaxe pro podpisy abstraktního typu člena je stejná jako v souborech podpisů a která je zobrazena technologií IntelliSense v editoru editoru editoru visual Studio Code.

Následující kód znázorňuje abstraktní třídu Shape, která má dvě ne abstraktní odvozené třídy, Čtverec a kruh. Příklad ukazuje, jak používat abstraktní třídy, metody a vlastnosti. V příkladu abstraktní třída Obrazec představuje společné prvky konkrétní entity kruh a čtverec. Společné rysy všech obrazců (v dvojrozměrném souřadnicovém systému) jsou abstrahovány do třídy Obrazec: pozice v mřížce, úhel otočení a oblast a vlastnosti obvodu. Lze je přepsat, s výjimkou pozice, chování, u kterého se jednotlivé obrazce nemohou změnit.

Metodu otáčení lze přepsat, stejně jako ve třídě Circle, která je invariantní vzhledem k jeho symetrii. Takže ve třídě Circle je metoda otáčení nahrazena metodou, která nic nedělá.

// An abstract class that has some methods and properties defined
// and some left abstract.
[<AbstractClass>]
type Shape2D(x0: float, y0: float) =
    let mutable x, y = x0, y0
    let mutable rotAngle = 0.0

    // These properties are not declared abstract. They
    // cannot be overriden.
    member this.CenterX
        with get () = x
        and set xval = x <- xval

    member this.CenterY
        with get () = y
        and set yval = y <- yval

    // These properties are abstract, and no default implementation
    // is provided. Non-abstract derived classes must implement these.
    abstract Area: float with get
    abstract Perimeter: float with get
    abstract Name: string with get

    // This method is not declared abstract. It cannot be
    // overridden.
    member this.Move dx dy =
        x <- x + dx
        y <- y + dy

    // An abstract method that is given a default implementation
    // is equivalent to a virtual method in other .NET languages.
    // Rotate changes the internal angle of rotation of the square.
    // Angle is assumed to be in degrees.
    abstract member Rotate: float -> unit
    default this.Rotate(angle) = rotAngle <- rotAngle + angle

type Square(x, y, sideLengthIn) =
    inherit Shape2D(x, y)
    member this.SideLength = sideLengthIn
    override this.Area = this.SideLength * this.SideLength
    override this.Perimeter = this.SideLength * 4.
    override this.Name = "Square"

type Circle(x, y, radius) =
    inherit Shape2D(x, y)
    let PI = 3.141592654
    member this.Radius = radius
    override this.Area = PI * this.Radius * this.Radius
    override this.Perimeter = 2. * PI * this.Radius
    // Rotating a circle does nothing, so use the wildcard
    // character to discard the unused argument and
    // evaluate to unit.
    override this.Rotate(_) = ()
    override this.Name = "Circle"

let square1 = new Square(0.0, 0.0, 10.0)
let circle1 = new Circle(0.0, 0.0, 5.0)
circle1.CenterX <- 1.0
circle1.CenterY <- -2.0
square1.Move -1.0 2.0
square1.Rotate 45.0
circle1.Rotate 45.0
printfn "Perimeter of square with side length %f is %f, %f" (square1.SideLength) (square1.Area) (square1.Perimeter)
printfn "Circumference of circle with radius %f is %f, %f" (circle1.Radius) (circle1.Area) (circle1.Perimeter)

let shapeList: list<Shape2D> = [ (square1 :> Shape2D); (circle1 :> Shape2D) ]
List.iter (fun (elem: Shape2D) -> printfn "Area of %s: %f" (elem.Name) (elem.Area)) shapeList

Výstup:

Perimeter of square with side length 10.000000 is 40.000000
Circumference of circle with radius 5.000000 is 31.415927
Area of Square: 100.000000
Area of Circle: 78.539816

Viz také