Herança (Guia de Programação em C#)

A herança, juntamente com o encapsulamento e polimorfismo, é uma das três principais características (ou pilares) da programação orientada a objeto. A herança permite que você criar novas classes para reutilizar, estendem e modificar o comportamento que está definido no outras classes. A classe cujos membros são herdados é chamada a classe base, e a classe que herda esses membros é chamada a classe derivada. Uma classe derivada pode ter somente uma classe base direta. No entanto, a herança é transitiva. Se ClassC é derivada da ClassB e ClassB é derivada da ClassA, ClassC herda os membros declarados em ClassB e ClassA.

Dica

Structs não oferecem suporte a herança, mas eles podem implementar interfaces.Para obter mais informações, consulte Interfaces (Guia de Programação em C#).

Conceitualmente, uma classe derivada é uma especialização da classe base. Por exemplo, se você tiver uma classe base Animal, você pode ter uma classe derivada chamado Mammal e outra classe derivada chamado Reptile. A Mammal é um Animale um Reptile é um Animal, mas cada classe derivada representa diferentes especializações da classe base.

Quando você Definir uma classe para derivar de outra classe, a classe derivada implicitamente obtém todos os membros da classe base, exceto para o construtores e destrutores. A classe derivada, assim, pode reutilizar o código na classe base sem ter que reimplementar a ele. Na classe derivada, você pode adicionar mais membros. Dessa forma, a classe derivada estende a funcionalidade da classe base.

A ilustração a seguir mostra uma classe WorkItem que representa um item de trabalho em algum processo de negócios. Como todas as classes, ele deriva de Object e herda todos os seus métodos. WorkItemadiciona cinco membros de sua própria. Eles incluem um construtor, porque os construtores não são herdadas. Classe ChangeRequest herda de WorkItem e representa um determinado tipo de item de trabalho. ChangeRequestadiciona dois membros de mais para os membros que ele herda de WorkItem de Object. Ele deve adicionar seu próprio construtor e também adiciona originalItemID. Propriedade originalItemID permite que o ChangeRequest instância a ser associado ao original WorkItem ao qual a solicitação de alteração se aplica.

Herança de classe

Herança da Classe

O exemplo a seguir mostra como as relações de classe demonstradas na ilustração anterior são expressas em C#. O exemplo também mostra como WorkItem substitui o método virtual Object.ToStringe como o ChangeRequest classe herda de WorkItem implementação do método.

// WorkItem implicitly inherits from the Object class. 
public class WorkItem
{
    // Static field currentID stores the job ID of the last WorkItem that 
    // has been created. 
    private static int currentID;

    //Properties. 
    protected int ID { get; set; }
    protected string Title { get; set; }
    protected string Description { get; set; }
    protected TimeSpan jobLength { get; set; }

    // Default constructor. If a derived class does not invoke a base- 
    // class constructor explicitly, the default constructor is called 
    // implicitly.  
    public WorkItem()
    {
        ID = 0;
        Title = "Default title";
        Description = "Default description.";
        jobLength = new TimeSpan();
    }

    // Instance constructor that has three parameters. 
    public WorkItem(string title, string desc, TimeSpan joblen)
    {
        this.ID = GetNextID();
        this.Title = title;
        this.Description = desc;
        this.jobLength = joblen;
    }

    // Static constructor to initialize the static member, currentID. This 
    // constructor is called one time, automatically, before any instance 
    // of WorkItem or ChangeRequest is created, or currentID is referenced. 
    static WorkItem()
    {
        currentID = 0;
    }


    protected int GetNextID()
    {
        // currentID is a static field. It is incremented each time a new 
        // instance of WorkItem is created. 
        return ++currentID;
    }

    // Method Update enables you to update the title and job length of an 
    // existing WorkItem object. 
    public void Update(string title, TimeSpan joblen)
    {
        this.Title = title;
        this.jobLength = joblen;
    }

    // Virtual method override of the ToString method that is inherited 
    // from System.Object. 
    public override string ToString()
    {
        return String.Format("{0} - {1}", this.ID, this.Title);
    }
}

// ChangeRequest derives from WorkItem and adds a property (originalItemID)  
// and two constructors. 
public class ChangeRequest : WorkItem
{
    protected int originalItemID { get; set; }

    // Constructors. Because neither constructor calls a base-class  
    // constructor explicitly, the default constructor in the base class 
    // is called implicitly. The base class must contain a default  
    // constructor. 

    // Default constructor for the derived class. 
    public ChangeRequest() { }

    // Instance constructor that has four parameters. 
    public ChangeRequest(string title, string desc, TimeSpan jobLen,
                         int originalID)
    {
        // The following properties and the GetNexID method are inherited  
        // from WorkItem. 
        this.ID = GetNextID();
        this.Title = title;
        this.Description = desc;
        this.jobLength = jobLen;

        // Property originalItemId is a member of ChangeRequest, but not  
        // of WorkItem. 
        this.originalItemID = originalID;
    }
}

class Program
{
    static void Main()
    {
        // Create an instance of WorkItem by using the constructor in the  
        // base class that takes three arguments.
        WorkItem item = new WorkItem("Fix Bugs",
                                     "Fix all bugs in my code branch",
                                     new TimeSpan(3, 4, 0, 0));

        // Create an instance of ChangeRequest by using the constructor in 
        // the derived class that takes four arguments.
        ChangeRequest change = new ChangeRequest("Change Base Class Design",
                                                 "Add members to the class",
                                                 new TimeSpan(4, 0, 0),
                                                 1);

        // Use the ToString method defined in WorkItem.
        Console.WriteLine(item.ToString());

        // Use the inherited Update method to change the title of the  
        // ChangeRequest object.
        change.Update("Change the Design of the Base Class",
            new TimeSpan(4, 0, 0));

        // ChangeRequest inherits WorkItem's override of ToString.
        Console.WriteLine(change.ToString());

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    1 - Fix Bugs
    2 - Change the Design of the Base Class
*/

Métodos abstratos e virtuais

Quando uma classe base declara um método como virtual, uma classe derivada pode Substituir o método com sua própria implementação. Se uma classe base declarar um membro como abstrata, que o método deve ser substituído em qualquer classe não-abstrata que herda diretamente a partir dessa classe. Se uma classe derivada é abstrato, ela herda membros abstratos sem ter que implementá-los. Os membros abstratos e virtuais são a base para o polimorfismo, que é a segunda característica principal da programação orientada a objeto. Para obter mais informações, consulte Polimorfismo (Guia de Programação em C#).

Classes Base abstratas

Você pode declarar uma classe como abstrata se você quiser impedir a instanciação direta usando o nova palavra-chave. Se você fizer isso, a classe pode ser usada somente se uma nova classe é derivada. Uma classe abstrata pode conter uma ou mais assinaturas de método que eles mesmos são declaradas como abstrato. Essas assinaturas de especificam os parâmetros e retornam o valor, mas não possuem implementação (corpo de método). Não tem uma classe abstrata conter membros abstratos; No entanto, se uma classe contiver um membro abstract, a própria classe deve ser declarada como abstrato. Classes derivadas que não são abstratas próprios devem fornecer a implementação de quaisquer métodos abstratos de uma classe base abstrata. Para obter mais informações, consulte Classes e membros de classes abstract e sealed (Guia de Programação em C#).

Interfaces

Um interface é um tipo de referência que é um pouco semelhante a uma classe base abstrata que consiste somente os membros abstratos. Quando uma classe implementa uma interface, ele deve fornecer uma implementação para todos os membros da interface. Uma classe pode implementar várias interfaces, mesmo que ele pode derivar de apenas uma única classe base direta.

Interfaces são usadas para definir recursos específicos para as classes que não têm necessariamente uma "é uma" relação. Por exemplo, o IEquatable interface pode ser implementada por qualquer classe ou struct que possui para habilitar o código do cliente determinar se dois objetos do tipo são equivalentes (no entanto, o tipo define equivalência). IEquatablenão implica o mesmo tipo de "é uma" relação existente entre uma classe base e uma classe derivada (por exemplo, um Mammal é um Animal). Para obter mais informações, consulte Interfaces (Guia de Programação em C#).

Acesso de classe derivada para membros de classe Base

Uma classe derivada tem acesso aos membros internos públicos, protegidos, internos e protegidos de uma classe base. Mesmo que uma classe derivada herda os membros privados de uma classe base, ele não pode acessar esses membros. No entanto, todos esses membros particulares ainda estão presentes na classe derivada e pode fazer o mesmo trabalho que eles fariam na própria classe base. Por exemplo, suponha que um método de classe base protegida acessa um campo particular. Esse campo deve estar presente na classe derivada para o método de classe base herdado funcione corretamente.

Impedindo a derivação de mais

Uma classe pode impedir que outras classes de herdar dele, ou de qualquer um de seus membros, declarando si mesmo ou o membro como lacrado. Para obter mais informações, consulte Classes e membros de classes abstract e sealed (Guia de Programação em C#).

Ocultação de classe derivada de membros de classe Base

Uma classe derivada pode ocultar os membros da classe base, declarando membros com o mesmo nome e assinatura. O nova modificador pode ser usado para indicar explicitamente que o membro não pretende ser uma substituição do membro base. O uso de nova não é necessária, mas um aviso de compilação será gerado se nova não é usado. Para obter mais informações, consulte Controle de versão com as palavras-chave override e new (Guia de Programação em C#) e Quando usar as palavras-chave override e new (Guia de Programação em C#).

Consulte também

Referência

Classes e structs (Guia de Programação em C#)

class (Referência de C#)

struct (Referência de C#)

Conceitos

Guia de Programação em C#