Compartilhar via


Classes abstratas

Classes abstratas são classes que deixam alguns ou todos os membros sem simplificação, para que as implementações possam ser fornecidas por classes derivadas.

Sintaxe

// 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

Observações

Na programação orientada a objetos, uma classe abstrata é usada como uma classe base de uma hierarquia e representa a funcionalidade comum de um conjunto diversificado de tipos de objeto. Como o nome "abstrato" implica, as classes abstratas geralmente não correspondem diretamente a entidades concretas no domínio do problema. No entanto, eles representam o que muitas entidades concretas diferentes têm em comum.

Classes abstratas devem ter o AbstractClass atributo. Eles podem ter membros implementados e não simplificados. O uso do termo abstrato quando aplicado a uma classe é o mesmo que em outros idiomas do .NET; no entanto, o uso do termo abstrato quando aplicado a métodos (e propriedades) é um pouco diferente em F# de seu uso em outras linguagens .NET. Em F#, quando um método é marcado com a abstract palavra-chave, isso indica que um membro tem uma entrada, conhecida como slot de expedição virtual, na tabela interna de funções virtuais para esse tipo. Em outras palavras, o método é virtual, embora a virtual palavra-chave não seja usada em F#. A palavra-chave abstract é usada em métodos virtuais, independentemente de o método ser implementado. A declaração de um slot de expedição virtual é separada da definição de um método para esse slot de expedição. Portanto, o equivalente F# de uma declaração e definição de método virtual em outra linguagem .NET é uma combinação de uma declaração de método abstrato e uma definição separada, com a default palavra-chave ou a override palavra-chave. Para obter mais informações e exemplos, consulte Métodos.

Uma classe será considerada abstrata somente se houver métodos abstratos declarados, mas não definidos. Portanto, classes que têm métodos abstratos não são necessariamente classes abstratas. A menos que uma classe tenha métodos abstratos indefinidos, não use o atributo AbstractClass .

Na sintaxe anterior, o modificador de acessibilidade pode ser public, private ou internal. Para obter mais informações, consulte Controle de Acesso.

Assim como acontece com outros tipos, classes abstratas podem ter uma classe base e uma ou mais interfaces base. Cada classe base ou interface aparece em uma linha separada junto com a inherit palavra-chave.

A definição de tipo de uma classe abstrata pode conter membros totalmente definidos, mas também pode conter membros abstratos. A sintaxe para membros abstratos é mostrada separadamente na sintaxe anterior. Nessa sintaxe, a assinatura de tipo de um membro é uma lista que contém os tipos de parâmetro em ordem e os tipos de retorno, separados por -> tokens e/ou * tokens conforme apropriado para parâmetros curried e tupled. A sintaxe para assinaturas de tipo de membro abstrato é a mesma usada em arquivos de assinatura e mostrada pelo IntelliSense no Editor do Visual Studio Code.

O código a seguir ilustra uma classe abstrata Shape, que tem duas classes derivadas não abstratas, Square e Circle. O exemplo mostra como usar classes abstratas, métodos e propriedades. No exemplo, a classe abstrata Shape representa os elementos comuns do círculo e do quadrado das entidades concretas. Os recursos comuns de todas as formas (em um sistema de coordenadas bidimensional) são abstraídos na classe Shape: a posição na grade, um ângulo de rotação e as propriedades de área e perímetro. Eles podem ser substituídos, exceto pela posição, o comportamento do qual as formas individuais não podem ser alteradas.

O método de rotação pode ser substituído, como na classe Circle, que é invariável de rotação devido à sua simetria. Portanto, na classe Circle, o método de rotação é substituído por um método que não faz nada.

// 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

Saída:

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

Consulte também