Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
As classes abstratas são classes que deixam alguns ou todos os membros não implementados, 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
Comentários
Na programação orientada a objeto, 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, elas representam o que muitas entidades concretas diferentes têm em comum.
Classes abstratas devem ter o atributo AbstractClass
. Elas podem ter membros implementados e não implementados. O uso do termo abstrato, quando aplicado a uma classe, é o mesmo que em outras linguagens do .NET. No entanto, o uso do termo abstrato aplicado a métodos (e propriedades) é um pouco diferente em F# do uso em outras linguagens do .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 expedição virtual na tabela interna de funções virtuais desse tipo. Em outras palavras, o método é virtual, embora a palavra-chave virtual
não seja usada em F#. A palavra-chave abstract
é usada em métodos virtuais, independentemente de sua implementação. 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 em F# de uma declaração e de uma definição de método virtual em outra linguagem do .NET é uma combinação de uma declaração de método abstrato e de uma definição separada, com a palavra-chave default
ou override
. Saiba mais e obtenha exemplos em 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 mais informações, consulte Controle de acesso.
Assim como acontece com outros tipos, as classes abstratas podem ter uma classe base e uma ou mais interfaces base. Cada interface ou classe base aparece em uma linha separada com a palavra-chave inherit
.
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 *
, conforme apropriado para parâmetros com curry ou tupla. 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, com 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 bidimensionais) 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, cujo comportamento as formas individuais não podem alterar.
O método de rotação pode ser substituído, como na classe Circle, que é invariante quanto à rotação devido à 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