CodeGym /Cursos /C# SELF /Sintaxe de herança e base

Sintaxe de herança e base em C#

C# SELF
Nível 20 , Lição 1
Disponível

1. Introdução

Nessa aula a gente vai ver como funciona a sintaxe de herança em C#: vamos aprender a declarar classes derivadas, entender o que é a palavra-chave base e como usar ela pra acessar a classe mãe. Isso não só vai facilitar tua vida na hora de usar código, mas também deixa o programa bem mais elegante (e às vezes até te deixa dormir mais tranquilo — porque não vai precisar ficar corrigindo erro de copiar-e-colar).

Olha um exemplo simples do dia a dia: temos uma classe Vehicle (veículo) — é o blueprintzão base, genérico. Todo veículo pode andar, tem cor, fabricante e tal:

public class Vehicle
{
    public string Brand { get; set; }
    public string Color { get; set; }

    public void Drive()
    {
        Console.WriteLine("Bora andar!");
    }
}
Classe base Vehicle

Agora, bora adicionar um novo tipo de transporte — carro. Carro ainda é um veículo, mas tem suas particularidades (tipo, número de portas). Seria estranho escrever tudo de novo sobre cor e fabricante, já que isso já tá definido!

Herança deixa a gente dizer: "Carro é um veículo, só que com um monte de coisa a mais."

2. Como declarar uma classe filha

Em C#, pra criar uma classe que herda de outra, a gente usa dois pontos :. Depois do nome da classe, diz de quem ela herda.


public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }
}
Declarando a classe filha Car

Lê assim: a classe Car herda todos os campos e métodos da classe Vehicle e ainda adiciona suas próprias paradas — tipo o número de portas.

Fica ligado: em C# só rola herança simples de classes (ou seja, uma classe só pode herdar de UMA mãe). Mas interface pode herdar de quantas tu quiser! (isso é papo pra depois).

Como funciona na prática?

Quando tu declara:

Car myCar = new Car();

...teu objeto myCar tem acesso tanto aos campos/métodos de Vehicle quanto às propriedades próprias dele. Exemplo:

myCar.Brand = "Toyota";
myCar.Color = "Azul";
myCar.NumberOfDoors = 4;
myCar.Drive(); // Método herdado

Cenário real:
No nosso app "em desenvolvimento", dava pra fazer um menu de veículos, onde o usuário escolhe o tipo de transporte e o programa mostra todas as propriedades dele. Quando tu adicionar um novo tipo de transporte, vai escrever o mínimo de código!

3. Herança de construtores

Quando a gente cria objetos da classe filha, às vezes quer inicializar as propriedades da classe base pelo construtor. Tipo, pra não esquecer de passar marca e cor:


public class Vehicle
{
    public string Brand { get; set; }
    public string Color { get; set; }

    public Vehicle(string brand, string color)
    {
        Brand = brand;
        Color = color;
    }
}

Agora, no construtor da filha, tu pode (e deve) chamar o construtor da mãe! Pra isso usa a palavra base:


public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }

    public Car(string brand, string color, int numberOfDoors)
        : base(brand, color) // chama o construtor de Vehicle!
    {
        NumberOfDoors = numberOfDoors;
    }
}

Como fica na prática?

Car bmw = new Car("BMW", "Preto", 4);
Console.WriteLine($"{bmw.Brand}, {bmw.Color}, portas: {bmw.NumberOfDoors}");
bmw.Drive(); // Continua funcionando!

Ou seja, bmw é carro e veículo ao mesmo tempo. Ele lembra dos "pais".

4. Diferença entre base e this

Em C# tem duas palavras-chave pra mexer com membros da classe: this e base.

  • this — acessa o objeto atual (tipo, o campo ou método dele mesmo).
  • baseacessa membro da classe mãe (ou seja, da mãe).

Quando usar base? Imagina que tu quer expandir a lógica de um método da mãe, ou só inicializar a mãe a partir da filha. Exemplo:


public class Bicycle : Vehicle
{
    public int NumberOfGears { get; set; }

    public Bicycle(string brand, string color, int gears)
        : base(brand, color)    // chama o construtor da mãe
    {
        NumberOfGears = gears;
    }

    public void ShowInfo()
    {
        // Usando propriedades da mãe!
        Console.WriteLine($"{Brand} ({Color}), marchas: {NumberOfGears}");
    }
}

5. Palavra-chave base em métodos

base não é só pra construtor! Às vezes tu quer mudar o comportamento de um método da mãe, mas ainda usar parte da lógica dela.

Tipo, queremos que o método Drive na classe Car também mostre qual carro estamos dirigindo:


public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }

    public Car(string brand, string color, int numberOfDoors) 
        : base(brand, color)
    {
        NumberOfDoors = numberOfDoors;
    }

    public void DriveCar()
    {
        base.Drive(); // chama a implementação da mãe
        Console.WriteLine($"Dirigindo {Brand} com {NumberOfDoors} portas!");
    }
}

Explicando:
Chamar base.Drive(); é tipo falar: "Mãe, conta tua parte da história primeiro, depois eu dou mais detalhes!". Então, quando chamar DriveCar() vai aparecer:

Bora andar!
Dirigindo BMW com 4 portas!

Sobre sobrescrever métodos (override) a gente fala nas próximas aulas :P

6. Esquema de herança

Bora visualizar as relações entre as classes. Olha um esqueminha simples (porque UML assusta de manhã cedo!):

Vehicle (base)
   /         \
Car      Bicycle
  • Todas as setas vão DA filha PRA mãe.
  • Todas as classes filhas têm acesso aos membros public/protected da mãe.

Diferença entre public, protected e private

Só pra lembrar, pra não confundir.
Na filha, tu enxerga:

Modificador Visível na filha?
public Sim
protected Sim
private Não

Erro comum:
Tentar acessar um campo private da mãe na filha:


public class Vehicle
{
    private string secret = "Ninguém vai saber!";
}

public class Car : Vehicle
{
    public void RevealSecret()
    {
        Console.WriteLine(secret); // Erro! Não enxerga.
    }
}
private — só pra mãe, segredo de família não vaza!

Comparando: base vs. filha

Vehicle Car (filha)
Brand tem herda
Color tem herda
Drive() tem herda (ou expande)
NumberOfDoors não próprio (propriedade única)

7. Exemplo

Se a gente continua evoluindo o appzinho "Controle de veículos", pode montar assim:


public class Vehicle
{
    public string Brand { get; set; }
    public string Color { get; set; }

    public Vehicle(string brand, string color)
    {
        Brand = brand;
        Color = color;
    }

    public void Drive()
    {
        Console.WriteLine($"{Brand} {Color} saiu andando!");
    }
}

public class Car : Vehicle
{
    public int NumberOfDoors { get; set; }

    public Car(string brand, string color, int numberOfDoors)
        : base(brand, color)
    {
        NumberOfDoors = numberOfDoors;
    }

    public void ShowCar()
    {
        Console.WriteLine($"Marca: {Brand}, Cor: {Color}, Portas: {NumberOfDoors}");
    }
}

public class Bicycle : Vehicle
{
    public int NumberOfGears { get; set; }

    public Bicycle(string brand, string color, int numberOfGears)
        : base(brand, color)
    {
        NumberOfGears = numberOfGears;
    }
}

No método principal dá pra criar uma lista de veículos e mostrar de jeitos diferentes:

Car ford = new Car("Ford", "Vermelho", 4);
ford.ShowCar();
ford.Drive();

Bicycle trek = new Bicycle("Trek", "Verde", 21);
trek.Drive();

8. Erros, pegadinhas e um pouco de zoeira

Erro muito comum — esquecer de chamar o construtor da mãe na filha. Se Vehicle não tem construtor sem parâmetro e tu não chamou base(...), vai dar erro de compilação: o compilador vai reclamar que não consegue inicializar a base. É tipo tentar construir o segundo andar sem o primeiro. Não rola. Tem que passar os dados pra cima.

Segundo erro: esquecer que campos/métodos da mãe marcados como private NÃO SÃO VISÍVEIS na filha. Se quiser deixar algo pros "filhos", usa protected (mais sobre isso nas próximas aulas).

E o principal: herança é massa, mas não inventa moda com hierarquia muito doida. Na vida real, se tua cadeia de herança tem mais de dois ou três níveis, provavelmente já deu ruim. É fácil se perder em quem herda de quem e pra quê tudo isso.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION