4
respostas

Nesse código o comportamento é o mesmo se tivesse usado as palavras virtual na classe base e na derivada ? Errei essa questão, pois não imaginava que ele iria chamar o método da classe filha uma vez que ele não está sobrescrevendo a rotina na classe pai.

public class Conta { public double Saldo { get; set; }

public double CalcularTaxaAdministrativa()
{
    return 1;
}

}

public class ContaCorrente : Conta { public double CalcularTaxaAdministrativa() { return 0; } }

4 respostas

Oi Bruno, não sou especialista, mas a explicação das alternativas ajudaram bastante. A mae precisa marcar o método como virtual e a filha precisa usar o override para indicar a sobreescrita. Dessa forma obrigada a pessoa a pensar sobre herança no momento do design da classe... Acho uma boa prática, na verdade.

Oi Alberto, entendi o que você disse, porém a minha dúvida é justamente nisso. Na classe "pai" não está como Virtual, como voce pode ver no código que colei e na filha não existe a sobrescrita. Tendo isso em mente, porque nesse código

public class Conta { public double Saldo { get; set; }

public double CalcularTaxaAdministrativa()
{
        return 1;
}

} public class ContaCorrente : Conta { public double CalcularTaxaAdministrativa() { return 0; } }

Ao fazer na Main: ContaCorrente c = new ContaCorrente (); c.CalcularTaxaAdministrativa(); <<

Ele retornaria 0 ao invés de um ? A explicação não ficou clara para mim. Achei que por não haver uma sobrescrita, ele executaria o método da classe pai.

Olá, Bruno. Tudo bom?

Vamos começar pelo código da Conta:

public class Conta
{ 
    public double Saldo { get; set; }

    public double CalcularTaxaAdministrativa()
    {
        return 1;
    }
}

Aqui dizemos ao compilador "A Classe Conta possui uma propriedade Saldo e um método não-virtual CalcularTaxaAdministrativa".

Quando temos uma referência de Conta, a aplicação não tem dúvidas, já sabe exatamente qual método executar, é este que retorna 1.

Agora, a ContaCorrente:

public class ContaCorrente : Conta 
{
    public double CalcularTaxaAdministrativa() 
    { 
        return 0;
    }
}

Aqui não falamos ao compilador que ContaCorrente possui a propriedade Saldo, só dizemos "A ContaCorrente é uma classe que define um método não-virtual CalcularTaxaAdministrativa" e aqui vale a mesma coisa, a aplicação, ao ver uma referência do tipo ContaCorrente já sabe imediatamente qual método chamar e é este que retorna 0.

Dado que, a partir de cada tipo de referência, a aplicação já sabe qual método executar, temos:

Conta conta = new Conta();
ContaCorrente corrente = new ContaCorrente();

conta.CalcularTaxaAdministrativa(); // 1
corrente.CalcularTaxaAdministrativa(); // 0

Parece razoável? O que acha?

Tudo o que falamos, foi em relação a referências do tipo Conta e ContaCorrente. Sabemos que, graças ao polimorfismo, podemos guardar um objeto do tipo ContaCorrente em uma referência do tipo Conta:

Conta conta = new ContaCorrente();

agora a saída de conta.CalcularTaxaAdministrativa(); será 1! E isso é porque estamos chamando o método CalcularTaxaAdministrativa a partir de uma referência do tipo Conta e, como falamos lá em cima, a aplicação (mais especificamente, a máquina virtual CLR) sabe exatamente qual método deve ser executado ao encontrar uma Conta - ele nem vai verificar o tipo do objeto e verificar os métodos da ContaCorrente, porque não existe outra opção.

Ótimo, agora, vamos ao caso em que usamos o virtual e o override:

public class Conta
{
    ...
    public virtual double CalcularTaxaAdministrativa() { ... }
}

public class ContaCorrente : Conta
{
    ...
    public override double CalcularTaxaAdministrativa() { ... }
}

Aqui falamos "A classe Conta possui um método virtual chamado CalcularTaxaAdministrativa" e agora as coisas mudaram. Como este método é virtual, a CLR não sabe exatamente qual método deverá executar com estas referências, então aqui haverá mais cuidado.

Também falamos "A classe ContaCorrente sobrescreve o método CalcularTaxaAdministrativa definido na classe base".

Agora, vamos ver o código abaixo:

Conta conta = AlgumMetodoQueDevolveUmaConta();
conta.CalcularTaxaAdministrativa();

(continua na próxima resposta)

(continuando)

Agora, vamos ver o código abaixo:

Conta conta = AlgumMetodoQueDevolveUmaConta();
conta.CalcularTaxaAdministrativa();

O que acontece nesta chamada? A CLR não sabe logo de cara! Depende do tipo do objeto retornado em AlgumMetodoQueDevolveUmaConta. Avisamos lá em cima que o método CalcularTaxaAdministrativa é virtual, então a aplicação não pode imediatamente visitar o tipo Conta e executar aquele código, afinal, este método pode ter sido sobrescrito em alguma classe derivada, então, somente quando avisamos que o método é virtual, a CLR vai verificar se o tipo do objeto possui uma sobrescrita neste método. Caso a sobrescrita não tenha sido feita, a CLR irá verificar se a classe derivada sobrescreveu e assim por diante, até chegarmos na definição em Conta.

Em resumo, quando não usamos virtual ou override:

Conta conta = new Conta();
ContaCorrente corrente = new ContaCorrente();

conta.CalcularTaxaAdministrativa(); // Opa, vou executar o método em `Conta`
corrente.CalcularTaxaAdministrativa(); // Opa, vou executar o método em `ContaCorrente`

Conta teste = corrente;
teste.CalcularTaxaAdministrativa(); // Opa, vou executar o método em `Conta`!

Em resumo, quando usamos virtual ou override:

Conta teste = new ContaCorrente();

teste.CalcularTaxaAdministrativa(); // Puts, este método foi definido como `virtual`. 
// Só vou saber qual método devo executar quando, em tempo de execução,
// eu verificar o tipo do objeto em `teste` e checar se houve uma sobrescrita!

Beleza? Bacana você ter perguntado. Este assunto é um pouco complicado mesmo. O que você acha? Fez sentido?

Abs.