Polimorfismo (Guia de Programação em C#)Polymorphism (C# Programming Guide)

O polimorfismo costuma ser chamado de o terceiro pilar da programação orientada a objetos, depois do encapsulamento e a herança.Polymorphism is often referred to as the third pillar of object-oriented programming, after encapsulation and inheritance. O polimorfismo é uma palavra grega que significa "de muitas formas" e tem dois aspectos distintos:Polymorphism is a Greek word that means "many-shaped" and it has two distinct aspects:

  • Em tempo de execução, os objetos de uma classe derivada podem ser tratados como objetos de uma classe base, em locais como parâmetros de método, coleções e matrizes.At run time, objects of a derived class may be treated as objects of a base class in places such as method parameters and collections or arrays. Quando isso ocorre, o tipo declarado do objeto não é mais idêntico ao seu tipo de tempo de execução.When this occurs, the object's declared type is no longer identical to its run-time type.

  • As classes base podem definir e implementar métodos virtuais e as classes derivadas podem substituí-los, o que significa que elas fornecem sua própria definição e implementação.Base classes may define and implement virtual methods, and derived classes can override them, which means they provide their own definition and implementation. Em tempo de execução, quando o código do cliente chama o método, o CLR procura o tipo de tempo de execução do objeto e invoca a substituição do método virtual.At run-time, when client code calls the method, the CLR looks up the run-time type of the object, and invokes that override of the virtual method. Dessa forma, você pode chamar em seu código-fonte um método de uma classe base e fazer com que a versão de uma classe derivada do método seja executada.Thus in your source code you can call a method on a base class, and cause a derived class's version of the method to be executed.

Os métodos virtuais permitem que você trabalhe com grupos de objetos relacionados de maneira uniforme.Virtual methods enable you to work with groups of related objects in a uniform way. Por exemplo, suponha que você tem um aplicativo de desenho que permite que um usuário crie vários tipos de formas sobre uma superfície de desenho.For example, suppose you have a drawing application that enables a user to create various kinds of shapes on a drawing surface. Você não sabe em tempo de compilação que tipos específicos de formas que o usuário criará.You do not know at compile time which specific types of shapes the user will create. No entanto, o aplicativo precisa manter controle de todos os diferentes tipos de formas que são criados e atualizá-los em resposta às ações do mouse do usuário.However, the application has to keep track of all the various types of shapes that are created, and it has to update them in response to user mouse actions. Você pode usar o polimorfismo para resolver esse problema em duas etapas básicas:You can use polymorphism to solve this problem in two basic steps:

  1. Crie uma hierarquia de classes em que cada classe de forma específica derive de uma classe base comum.Create a class hierarchy in which each specific shape class derives from a common base class.

  2. Use um método virtual para invocar o método adequado em qualquer classe derivada por meio de uma única chamada para o método da classe base.Use a virtual method to invoke the appropriate method on any derived class through a single call to the base class method.

Primeiro, crie uma classe base chamada Shape e as classes derivadas como Rectangle, Circle e Triangle.First, create a base class called Shape, and derived classes such as Rectangle, Circle, and Triangle. Atribua à classe Shape um método virtual chamado Draw e substitua-o em cada classe derivada para desenhar a forma especial que a classe representa.Give the Shape class a virtual method called Draw, and override it in each derived class to draw the particular shape that the class represents. Crie um objeto List<Shape> e adicione um círculo, triângulo e retângulo para ele.Create a List<Shape> object and add a Circle, Triangle and Rectangle to it. Para atualizar a superfície de desenho, use um loop foreach para iterar na lista e chamar o método Draw em cada objeto Shape na lista.To update the drawing surface, use a foreach loop to iterate through the list and call the Draw method on each Shape object in the list. Mesmo que cada objeto na lista tenha um tipo de declaração de Shape, é o tipo de tempo de execução (a versão de substituição do método em cada classe derivada) que será invocado.Even though each object in the list has a declared type of Shape, it is the run-time type (the overridden version of the method in each derived class) that will be invoked.

using System;
using System.Collections.Generic;

public class Shape
{
    // A few example members
    public int X { get; private set; }
    public int Y { get; private set; }
    public int Height { get; set; }
    public int Width { get; set; }
   
    // Virtual method
    public virtual void Draw()
    {
        Console.WriteLine("Performing base class drawing tasks");
    }
}

class Circle : Shape
{
    public override void Draw()
    {
        // Code to draw a circle...
        Console.WriteLine("Drawing a circle");
        base.Draw();
    }
}
class Rectangle : Shape
{
    public override void Draw()
    {
        // Code to draw a rectangle...
        Console.WriteLine("Drawing a rectangle");
        base.Draw();
    }
}
class Triangle : Shape
{
    public override void Draw()
    {
        // Code to draw a triangle...
        Console.WriteLine("Drawing a triangle");
        base.Draw();
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Polymorphism at work #1: a Rectangle, Triangle and Circle
        // can all be used whereever a Shape is expected. No cast is
        // required because an implicit conversion exists from a derived 
        // class to its base class.
        var shapes = new List<Shape>
        {
            new Rectangle(),
            new Triangle(),
            new Circle()
        };

        // Polymorphism at work #2: the virtual method Draw is
        // invoked on each of the derived classes, not the base class.
        foreach (var shape in shapes)
        {
            shape.Draw();
        }

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

}

/* Output:
    Drawing a rectangle
    Performing base class drawing tasks
    Drawing a triangle
    Performing base class drawing tasks
    Drawing a circle
    Performing base class drawing tasks
 */

Em C#, cada tipo é polimórfico porque todos os tipos, incluindo tipos definidos pelo usuário, herdam de Object.In C#, every type is polymorphic because all types, including user-defined types, inherit from Object.

Visão Geral sobre o polimorfismoPolymorphism Overview

Membros virtuaisVirtual Members

Quando uma classe derivada herda de uma classe base, ela ganha todos os métodos, campos, propriedades e eventos da classe base.When a derived class inherits from a base class, it gains all the methods, fields, properties and events of the base class. O designer da classe derivada pode escolher entreThe designer of the derived class can choose whether to

  • substituir os membros virtuais na classe base,override virtual members in the base class,

  • herdar o método da classe base mais próxima, sem ignorá-loinherit the closest base class method without overriding it

  • definir nova implementação não virtual desses membros que ocultam as implementações da classe basedefine new non-virtual implementation of those members that hide the base class implementations

Uma classe derivada poderá substituir um membro de classe base somente se o membro da classe base tiver sido declarado como virtual ou abstrato.A derived class can override a base class member only if the base class member is declared as virtual or abstract. O membro derivado deve usar a palavra-chave override para indicar explicitamente que o método destina-se a participar da invocação virtual.The derived member must use the override keyword to explicitly indicate that the method is intended to participate in virtual invocation. O código a seguir mostra um exemplo:The following code provides an example:

public class BaseClass
{
    public virtual void DoWork() { }
    public virtual int WorkProperty
    {
        get { return 0; }
    }
}
public class DerivedClass : BaseClass
{
    public override void DoWork() { }
    public override int WorkProperty
    {
        get { return 0; }
    }
}

Os campos não podem ser virtuais, apenas os métodos, propriedades, eventos e indexadores podem ser virtuais.Fields cannot be virtual; only methods, properties, events and indexers can be virtual. Quando uma classe derivada substitui um membro virtual, esse membro é chamado, mesmo quando uma instância dessa classe está sendo acessada como uma instância da classe base.When a derived class overrides a virtual member, that member is called even when an instance of that class is being accessed as an instance of the base class. O código a seguir mostra um exemplo:The following code provides an example:

DerivedClass B = new DerivedClass();
B.DoWork();  // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork();  // Also calls the new method.

Os métodos e propriedades virtuais permitem que classes derivadas estendam uma classe base sem a necessidade de usar a implementação da classe base de um método.Virtual methods and properties enable derived classes to extend a base class without needing to use the base class implementation of a method. Para obter mais informações, consulte Controle de versão com as palavras-chave override e new.For more information, see Versioning with the Override and New Keywords. Uma interface fornece uma outra maneira de definir um método ou conjunto de métodos cuja implementação é deixada para classes derivadas.An interface provides another way to define a method or set of methods whose implementation is left to derived classes. Para obter mais informações, consulte Interfaces.For more information, see Interfaces.

Ocultando membros de classe base com novos membrosHiding Base Class Members with New Members

Se você quiser que o seu membro derivado tenha o mesmo nome de um membro de uma classe base, mas não quiser que ele participe da invocação virtual, será possível usar a palavra-chave new.If you want your derived member to have the same name as a member in a base class, but you do not want it to participate in virtual invocation, you can use the new keyword. A palavra-chave new é colocada antes do tipo de retorno de um membro de classe que está sendo substituído.The new keyword is put before the return type of a class member that is being replaced. O código a seguir mostra um exemplo:The following code provides an example:

public class BaseClass
{
    public void DoWork() { WorkField++; }
    public int WorkField;
    public int WorkProperty
    {
        get { return 0; }
    }
}

public class DerivedClass : BaseClass
{
    public new void DoWork() { WorkField++; }
    public new int WorkField;
    public new int WorkProperty
    {
        get { return 0; }
    }
}

Você ainda pode acessar os membros da classe base ocultos a partir do código do cliente, convertendo a instância da classe derivada a uma instância da classe base.Hidden base class members can still be accessed from client code by casting the instance of the derived class to an instance of the base class. Por exemplo:For example:

DerivedClass B = new DerivedClass();
B.DoWork();  // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork();  // Calls the old method.

Impedindo que classes derivadas substituam membros virtuaisPreventing Derived Classes from Overriding Virtual Members

Os membros virtuais permanecem virtuais por tempo indeterminado, independentemente de quantas classes foram declaradas entre o membro virtual e a classe que originalmente o declarou.Virtual members remain virtual indefinitely, regardless of how many classes have been declared between the virtual member and the class that originally declared it. Se a classe A declara um membro virtual, a classe B deriva de A e a classe C deriva de B, a classe C herda o membro virtual e tem a opção de substituí-lo, independentemente de a classe B ter declarado uma substituição para esse membro.If class A declares a virtual member, and class B derives from A, and class C derives from B, class C inherits the virtual member, and has the option to override it, regardless of whether class B declared an override for that member. O código a seguir mostra um exemplo:The following code provides an example:

public class A
{
    public virtual void DoWork() { }
}
public class B : A
{
    public override void DoWork() { }
}

Uma classe derivada pode interromper a herança virtual, declarando uma substituição como sealed.A derived class can stop virtual inheritance by declaring an override as sealed. Isso exige a colocação da palavra-chave sealed antes da palavra-chave override na declaração de membro de classe.This requires putting the sealed keyword before the override keyword in the class member declaration. O código a seguir mostra um exemplo:The following code provides an example:

public class C : B
{
    public sealed override void DoWork() { }
}

No exemplo anterior, o método DoWork não será mais virtual para qualquer classe derivada de C. Ele ainda será virtual para instâncias de C, mesmo se elas forem convertidas em métodos tipo B ou tipo A. Métodos lacrados podem ser substituídos por classes derivadas usando a palavra-chave new, como mostra o exemplo a seguir:In the previous example, the method DoWork is no longer virtual to any class derived from C. It is still virtual for instances of C, even if they are cast to type B or type A. Sealed methods can be replaced by derived classes by using the new keyword, as the following example shows:

public class D : C
{
    public new void DoWork() { }
}

Neste caso, se DoWork é chamado em D usando uma variável do tipo D, o novo DoWork é chamado.In this case, if DoWork is called on D using a variable of type D, the new DoWork is called. Se uma variável do tipo C, B ou A é usada para acessar uma instância de D, uma chamada de DoWork seguirá as regras de herança virtual, encaminhando as chamadas para a implementação de DoWork na classe C.If a variable of type C, B, or A is used to access an instance of D, a call to DoWork will follow the rules of virtual inheritance, routing those calls to the implementation of DoWork on class C.

Acessando membros virtuais da classe base das classes derivadasAccessing Base Class Virtual Members from Derived Classes

A classe derivada que substituiu um método ou propriedade ainda pode acessar o método ou propriedade na classe base usando a palavra-chave base.A derived class that has replaced or overridden a method or property can still access the method or property on the base class using the base keyword. O código a seguir mostra um exemplo:The following code provides an example:

public class Base
{
    public virtual void DoWork() {/*...*/ }
}
public class Derived : Base
{
    public override void DoWork()
    {
        //Perform Derived's work here
        //...
        // Call DoWork on base class
        base.DoWork();
    }
}

Para obter mais informações, consulte base.For more information, see base.

Observação

Recomendamos que os membros virtuais usem base para chamar a implementação da classe base do membro em sua própria implementação.It is recommended that virtual members use base to call the base class implementation of that member in their own implementation. Deixar o comportamento da classe base ocorrer permite que a classe derivada se concentre na implementação de comportamento específico para a classe derivada.Letting the base class behavior occur enables the derived class to concentrate on implementing behavior specific to the derived class. Se a implementação da classe base não é chamado, cabe à classe derivada tornar seu comportamento compatível com o comportamento da classe base.If the base class implementation is not called, it is up to the derived class to make their behavior compatible with the behavior of the base class.

Nesta seçãoIn This Section

Consulte tambémSee also