Partilhar via


Aulas abstratas

Classes abstratas são classes que deixam alguns ou todos os membros não implementados, de modo que as implementações podem 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 objetos. Como o nome "abstrato" implica, as classes abstratas muitas vezes não correspondem diretamente a entidades concretas no domínio do problema. No entanto, representam o que muitas entidades concretas diferentes têm em comum.

As classes abstratas devem ter o AbstractClass atributo. Podem ter membros implementados e não implementados. O uso do termo resumo quando aplicado a uma classe é o mesmo que em outras linguagens .NET, no entanto, o uso do termo resumo 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 palavra-chave abstract , isso indica que um membro tem uma entrada, conhecida como slot de despacho 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 uma ranhura de expedição virtual é distinta da definição de um método para essa ranhura de expedição. Portanto, o equivalente F# de uma declaração de método virtual e definição 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 é considerada abstrata somente se houver métodos abstratos que são 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.

Tal como acontece com outros tipos, as 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. Nesta sintaxe, a assinatura de tipo de um membro é uma lista que contém os tipos de parâmetros 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 de Códigos do Visual Studio.

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 das entidades concretas círculo e quadrado. As características comuns de todas as formas (em um sistema de coordenadas bidimensionais) são abstraídas na classe Shape: a posição na grade, um ângulo de rotação e as propriedades de área e perímetro. Estes podem ser substituídos, exceto pela posição, cujo comportamento as formas individuais não podem mudar.

O método de rotação pode ser substituído, como na classe Circle, que é invariante de rotação devido à sua simetria. Assim, 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