Compartilhar via


abstract (Referência de C#)

O abstract modificador indica que seu destino tem uma implementação ausente ou incompleta. Use o modificador abstrato com classes, métodos, propriedades, indexadores e eventos. Use o modificador abstract em uma declaração de classe para indicar que uma classe se destina somente a ser uma classe base de outras classes, não instanciada por conta própria. Classes não abstratas que derivam da classe abstrata devem implementar membros marcados como abstratos.

A linguagem C# faz referência a documentos da versão mais recentemente lançada da linguagem C#. Ele também contém a documentação inicial para funcionalidades em pré-visualizações públicas para o próximo lançamento do idioma.

A documentação identifica qualquer recurso introduzido pela primeira vez nas três últimas versões do idioma ou nas versões prévias públicas atuais.

Dica

Para descobrir quando um recurso foi introduzido pela primeira vez em C#, consulte o artigo sobre o histórico de versão da linguagem C#.

Classes abstratas podem conter membros abstratos (que não têm implementação e devem ser substituídos em classes derivadas) e membros totalmente implementados (como métodos regulares, propriedades e construtores). Esse recurso permite que classes abstratas forneçam funcionalidade comum enquanto ainda exigem classes derivadas para implementar membros abstratos específicos.

Observação

Os membros da interface são abstract por padrão.

Classe abstrata com membros mistos

O exemplo a seguir demonstra uma classe abstrata que contém métodos implementados e membros abstratos:

namespace LanguageKeywords;

public abstract class Vehicle
{
    protected string _brand;
    
    // Constructor - implemented method in abstract class
    public Vehicle(string brand) => _brand = brand;
    
    // Implemented method - provides functionality that all vehicles share
    public string GetInfo() => $"This is a {_brand} vehicle.";
    
    // Another implemented method
    public virtual void StartEngine() => Console.WriteLine($"{_brand} engine is starting...");
    
    // Abstract method - must be implemented by derived classes
    public abstract void Move();
    
    // Abstract property - must be implemented by derived classes  
    public abstract int MaxSpeed { get; }
}

public class Car : Vehicle
{
    public Car(string brand) : base(brand) { }
    
    // Implementation of abstract method
    public override void Move() => Console.WriteLine($"{_brand} car is driving on the road.");
    
    // Implementation of abstract property
    public override int MaxSpeed => 200;
}

public class Boat : Vehicle
{
    public Boat(string brand) : base(brand) { }
    
    // Implementation of abstract method
    public override void Move() => Console.WriteLine($"{_brand} boat is sailing on the water.");
    
    // Implementation of abstract property
    public override int MaxSpeed => 50;
}

public class AbstractExample
{
    public static void Examples()
    {
        // Cannot instantiate abstract class: Vehicle v = new Vehicle("Generic"); // Error!
        
        Car car = new Car("Toyota");
        Boat boat = new Boat("Yamaha");
        
        // Using implemented methods from abstract class
        Console.WriteLine(car.GetInfo());
        car.StartEngine();
        
        // Using abstract methods implemented in derived class
        car.Move();
        Console.WriteLine($"Max speed: {car.MaxSpeed} km/h");
        
        Console.WriteLine();
        
        Console.WriteLine(boat.GetInfo());
        boat.StartEngine();
        boat.Move();
        Console.WriteLine($"Max speed: {boat.MaxSpeed} km/h");
    }
}

class Program
{
    static void Main()
    {
        AbstractExample.Examples();
    }
}
/* Output:
This is a Toyota vehicle.
Toyota engine is starting...
Toyota car is driving on the road.
Max speed: 200 km/h

This is a Yamaha vehicle.
Yamaha engine is starting...
Yamaha boat is sailing on the water.
Max speed: 50 km/h
*/

Neste exemplo, a Vehicle classe abstrata fornece:

  • Membros implementados: GetInfo() método, StartEngine() método e construtor – esses membros fornecem funcionalidade comum para todos os veículos.
  • Membros abstratos: Move() método e MaxSpeed propriedade – esses membros devem ser implementados por cada tipo de veículo específico.

Esse design permite que a classe abstrata forneça funcionalidade compartilhada, garantindo que as classes derivadas implementem um comportamento específico do veículo.

Classe concreta derivada de uma classe abstrata

Neste exemplo, a classe Square deve fornecer uma implementação de GetArea porque deriva de Shape:

abstract class Shape
{
    public abstract int GetArea();
}

class Square : Shape
{
    private int _side;

    public Square(int n) => _side = n;

    // GetArea method is required to avoid a compile-time error.
    public override int GetArea() => _side * _side;

    static void Main()
    {
        var sq = new Square(12);
        Console.WriteLine($"Area of the square = {sq.GetArea()}");
    }
}
// Output: Area of the square = 144

As classes abstratas têm os seguintes recursos:

  • Você não pode criar uma instância de uma classe abstrata.
  • Uma classe abstrata pode conter métodos abstratos e acessadores.
  • Uma classe abstrata também pode conter métodos, propriedades, campos e outros membros implementados que fornecem funcionalidade para classes derivadas.
  • Você não pode usar o sealed modificador em uma classe abstrata porque os dois modificadores têm significados opostos. O modificador sealed impede que uma classe seja herdada e o modificador abstract requer uma classe a ser herdada.
  • Uma classe não abstrata derivada de uma classe abstrata deve incluir implementações reais de todos os acessadores e métodos abstratos herdados.

Use o abstract modificador em um método ou declaração de propriedade para indicar que o método ou a propriedade não contém implementação.

Os métodos abstratos têm os seguintes recursos:

  • Um método abstrato é implicitamente um método virtual.

  • Declarações de método abstrato são permitidas apenas em classes abstratas.

  • Como uma declaração de método abstrato não fornece nenhuma implementação real, não há nenhum corpo do método. A declaração do método simplesmente termina com um ponto-e-vírgula. Por exemplo:

    public abstract void MyMethod();
    

    A implementação é fornecida por um método override, que é membro de uma classe não abstrata.

  • É um erro usar os static modificadores em virtual uma declaração de método abstrato em um class tipo. Você pode declarar static abstract e static virtual métodos em interfaces.

    Propriedades abstratas se comportam como métodos abstratos, exceto pelas diferenças na sintaxe de declaração e chamada.

  • É um erro usar o abstract modificador em uma propriedade estática em um class tipo. Você pode declarar static abstract ou static virtual propriedades em declarações de interface.

  • Uma propriedade herdada abstrata pode ser substituída em uma classe derivada, incluindo uma declaração de propriedade que usa o override modificador.

Para obter mais informações sobre classes abstratas, consulte Classes e membros de classes abstratos e lacrados.

Uma classe abstrata deve fornecer uma implementação para todos os membros de interface. Uma classe abstrata que implementa uma interface pode mapear os métodos de interface em métodos abstratos. Por exemplo:

interface I
{
    void M();
}

abstract class C : I
{
    public abstract void M();
}

No exemplo a seguir, a classe DerivedClass deriva de uma classe BaseClassabstrata. A classe abstrata contém um método abstrato, AbstractMethod e duas propriedades abstratas, X e Y.

// Abstract class
abstract class BaseClass
{
    protected int _x = 100;
    protected int _y = 150;

    // Abstract method
    public abstract void AbstractMethod();

    // Abstract properties
    public abstract int X { get; }
    public abstract int Y { get; }
}

class DerivedClass : BaseClass
{
    public override void AbstractMethod()
    {
        _x++;
        _y++;
    }

    public override int X   // overriding property
    {
        get
        {
            return _x + 10;
        }
    }

    public override int Y   // overriding property
    {
        get
        {
            return _y + 10;
        }
    }

    static void Main()
    {
        var o = new DerivedClass();
        o.AbstractMethod();
        Console.WriteLine($"x = {o.X}, y = {o.Y}");
    }
}
// Output: x = 111, y = 161

No exemplo anterior, se você tentar instanciar a classe abstrata usando uma instrução como esta:

BaseClass bc = new BaseClass();   // Error

Você recebe um erro dizendo que o compilador não pode criar uma instância da classe abstrata 'BaseClass'. No entanto, você pode usar um construtor de classe abstrato, conforme mostrado no exemplo a seguir.

public abstract class Shape
{
    public string Color { get; set; }

    // Constructor of the abstract class
    protected Shape(string color)
    {
        Color = color;
        Console.WriteLine($"Created a shape with color {color}.");
    }

    // Abstract method that must be implemented by derived classes
    public abstract double CalculateArea();
}

public class Square : Shape
{
    public double Side { get; set; }

    // Constructor of the derived class calling the base class constructor
    public Square(string color, double side) : base(color)
    {
        Side = side;
    }

    public override double CalculateArea()
    {
        return Side * Side;
    }
}

public class Program
{
    public static void Main(string[] args)
     {
            Square square = new Square("red", 5);
            Console.WriteLine($"Area of the square: {square.CalculateArea()}");            
     }
}

A Shape classe é declarada abstract, o que significa que você não pode instanciá-la diretamente. Em vez disso, ele serve como um modelo para outras classes.

  • Mesmo que você não possa criar objetos de uma classe abstrata, ela ainda pode ter um construtor. Esse construtor normalmente protectedé , o que significa que somente classes derivadas podem acessá-lo. Nesse caso, o construtor Shape usa um parâmetro color e inicializa a propriedade Color. Ele também imprime uma mensagem no console. A parte public Square(string color, double side) : base(color) chama o construtor da classe base (Shape) e passa o argumento color para ele.
  • Shape Na classe, o construtor definido usa uma cor como parâmetroprotected Shape(string color). Isso significa que o C# não fornece mais um construtor sem parâmetros padrão automaticamente. Classes derivadas devem usar a : base(color) expressão para invocar o construtor base. Definir o valor padrão como cor protected Shape(string color="green") permite omitir a : base(color) expressão em classes derivadas. O construtor protected Shape(string color="green") define a cor como verde.

Especificação da Linguagem C#

Para obter mais informações, consulte a Especificação da linguagem C#. A especificação da linguagem é a fonte definitiva para a sintaxe e o uso de C#.

Confira também