Esse post não será mais atualizado nesse blog. Para visualizar esse post em seu novo endereço, acesse:
http://milaneze.com.br/post/2009/06/28/C-Classes-abstratas.aspx
Uma classe abstrata é utilizada quando deseja-se fornecer uma interface comum a diversos membros de uma hierarquia de classes. Os métodos declarados na classe abstrata serão implementados em suas subclasses, através de
polimorfismo.
É importante salientar que uma classe abstrata não pode ser instanciada. Uma classe que contenha métodos abstratos deve ser declarada como
abstract mesmo que contenha métodos concretos.
Abaixo, temos um exemplo de classe abstrata com um método abstrato. Na linha 44 é definido o método abstrato. Esse método deverá ser implementado nas classes derivadas da classe Empregado.
1: abstract class Empregado
2: { 3: private string primeiroNome;
4: private string ultimoNome;
5: private string numeroSeguroSocial;
6:
7: public Empregado(string primeiro, string ultimo, string nss)
8: { 9: primeiroNome = primeiro;
10: ultimoNome = ultimo;
11: numeroSeguroSocial = nss;
12: }
13:
14: public string PrimeiroNome
15: { 16: get
17: { 18: return primeiroNome;
19: }
20: }
21:
22: public string UltimoNome
23: { 24: get
25: { 26: return ultimoNome;
27: }
28: }
29:
30: public string NumeroSeguroSocial
31: { 32: get
33: { 34: return numeroSeguroSocial;
35: }
36: }
37:
38: public override string ToString()
39: { 40: return string.Format("{0} {1}\nNúmero do Seguro Social: {3}", PrimeiroNome, UltimoNome, NumeroSeguroSocial); 41: }
42:
43: // método abstrato que será implementado pela classe derivada
44: public abstract decimal Salario();
45: }
Vamos utilizar como exemplo um sistema de folha de pagamento (exemplo do livro do Deitel) para implementar a classe Empregado utilizando polimorfismo. O código para implementação de uma classe abstrata é o mesmo da herança: ClasseAbstrata : ClasseDerivada.
Abaixo, o diagrama de classes do sistema de folha de pagamento (sem os métodos e atributos):

O código abaixo é da classe derivada EmpregadoAssalariado. Na linha 1 está o código que informa que a classe EmpregadoAssalariado implementa a classe Empregado.
1: class EmpregadoAssalariado : Empregado
2: { 3: private decimal salarioSemanal;
4:
5: public EmpregadoAssalariado(string primeiro, string ultimo, string nss, decimal salario)
6: : base(primeiro, ultimo, nss)
7: { 8: SalarioSemanal = salario;
9: }
10:
11: public decimal SalarioSemanal
12: { 13: get
14: { 15: return salarioSemanal;
16: }
17:
18: set
19: { 20: salarioSemanal = (value >= 0) ? value : 0;
21: }
22: }
23:
24: public override decimal Salario()
25: { 26: return SalarioSemanal;
27: }
28:
29: public override string ToString()
30: { 31: return string.Format( "Empregado assalariado: {0}\n{1}: {2:C}", base.ToString(), "salário semanal", SalarioSemanal); 32: }
33: }
Agora, a implementação da classe
EmpregadoPagoPorHora 1: class EmpregadoPagoPorHora : Empregado
2: { 3: private decimal salarioPorHora;
4: private decimal horas;
5:
6: public EmpregadoPagoPorHora(string primeiro, string ultimo, string nss, decimal salarioPorHora, decimal horasTrabalhadas)
7: : base(primeiro, ultimo, nss)
8: { 9: SalarioPorHora = salarioPorHora;
10: Horas = horasTrabalhadas;
11: }
12:
13: public decimal SalarioPorHora
14: { 15: get
16: { 17: return salarioPorHora;
18: }
19:
20: set
21: { 22: salarioPorHora = (value >= 0) ? value : 0;
23: }
24: }
25:
26: public decimal Horas
27: { 28: get
29: { 30: return horas;
31: }
32:
33: set
34: { 35: horas = (value >= 0) ? value : 0;
36: }
37: }
38:
39: public override decimal Salario()
40: { 41: if (Horas <= 40) //sem horas extras
42: return SalarioPorHora * Horas;
43: else
44: return (40 * SalarioPorHora) + ((Horas - 40) * SalarioPorHora * 1.5M);
45: }
46:
47: public override string ToString()
48: { 49: return string.Format("empregado pago por hora: {0}\n{1}: {2:C}; {3}: {4:F2}", base.ToString(), "salário por hora", SalarioPorHora, "horas trabalhadas", Horas); 50: }
51: }
Em seguida, a implementação da classe
EmpregadoComissionado:
1: class EmpregadoComissionado : Empregado
2: { 3: private decimal vendaBruta;
4: private decimal taxaDeComissao;
5:
6: public EmpregadoComissionado(string primeiro, string ultimo, string nss, decimal vendas, decimal taxa)
7: : base(primeiro, ultimo, nss)
8: { 9: VendaBruta = vendas;
10: TaxaDeComissao = taxa;
11: }
12:
13: public decimal TaxaDeComissao
14: { 15: get
16: { 17: return taxaDeComissao;
18: }
19:
20: set
21: { 22: taxaDeComissao = (value > 0 && value < 1) ? value : 0;
23: }
24: }
25:
26: public decimal VendaBruta
27: { 28: get
29: { 30: return vendaBruta;
31: }
32:
33: set
34: { 35: vendaBruta = (value >= 0) ? value : 0;
36: }
37: }
38:
39: public override decimal Salario()
40: { 41: return TaxaDeComissao * VendaBruta;
42: }
43:
44: public override string ToString()
45: { 46: return string.Format( "{0}: {1}\n{2}: {3:C}\n{4}: {5:F2}", "empregado comissionado", base.ToString(), "venda bruta", VendaBruta, "taxa de comissão", TaxaDeComissao); 47: }
48: }
A classe
EmpregadoComissionadoMaisSalarioBase é uma classe derivada da classe
EmpregadoComissionado e, por consequência, também implementa o método abstrato da classe
Empregado.
1: class EmpregadoComissionadoMaisSalarioBase : EmpregadoComissionado
2: { 3: private decimal salarioBase;
4:
5: public EmpregadoComissionadoMaisSalarioBase(string primeiro, string ultimo, string nss, decimal vendas, decimal taxa, decimal salario)
6: : base(primeiro, ultimo, nss, vendas, taxa)
7: { 8: SalarioBase = salario;
9: }
10:
11: public decimal SalarioBase
12: { 13: get
14: { 15: return salarioBase;
16: }
17:
18: set
19: { 20: salarioBase = (value >= 0) ? value : 0;
21: }
22: }
23:
24: public override decimal Salario()
25: { 26: return base.Salario();
27: }
28:
29: public override string ToString()
30: { 31: return string.Format( "{0} {1}; {2}: {3:C}", "com salário base", base.ToString(), "salário base", SalarioBase); 32: }
33: }
Agora chegou a hora de implementar esse código para entender como ele irá funcionar.
1: class Program
2: { 3: static void Main(string[] args)
4: { 5: EmpregadoAssalariado empregadoAssalariado = new EmpregadoAssalariado("John", "Smith", "111-11-1111", 800.00M); 6: EmpregadoPagoPorHora empregadoPagoPorHora = new EmpregadoPagoPorHora("Karen", "Price", "222-22-2222", 16.75M, 40.0M); 7: EmpregadoComissionado empregadoComissionado = new EmpregadoComissionado("Sue", "Jones", "333-33-3333", 10000.00M, .06M); 8: EmpregadoComissionadoMaisSalarioBase empregadoComissionadoMaisSalarioBase = new EmpregadoComissionadoMaisSalarioBase("Bob", "Lewis", "444-44-4444", 5000.00M, .04M, 300.00M); 9:
10: Console.WriteLine("Empregados processados individualmente:\n"); 11: Console.WriteLine("{0}\n{1}: {2:C}\n", empregadoAssalariado, "earned", empregadoAssalariado.Salario()); 12: Console.WriteLine("{0}\n{1}: {2:C}\n", empregadoPagoPorHora, "earned", empregadoPagoPorHora.Salario()); 13: Console.WriteLine("{0}\n{1}: {2:C}\n", empregadoComissionado, "earned", empregadoComissionado.Salario()); 14: Console.WriteLine("{0}\n{1}: {2:C}\n", empregadoComissionadoMaisSalarioBase, "earned", empregadoComissionadoMaisSalarioBase.Salario()); 15:
16: Empregado[] empregados = new Empregado[4];
17: empregados[0] = empregadoAssalariado;
18: empregados[1] = empregadoPagoPorHora;
19: empregados[2] = empregadoComissionado;
20: empregados[3] = empregadoComissionadoMaisSalarioBase;
21:
22: Console.WriteLine("Empregados processados polimorficamente:\n"); 23:
24: foreach (Empregado empregadoAtual in empregados)
25: { 26: Console.WriteLine(empregadoAtual);
27:
28: if (empregadoAtual is EmpregadoComissionadoMaisSalarioBase)
29: { 30: EmpregadoComissionadoMaisSalarioBase empregado = (EmpregadoComissionadoMaisSalarioBase)empregadoAtual;
31: empregado.SalarioBase *= 1.10M;
32: Console.WriteLine("Novo salário base com 10% de aumento: " + empregado.SalarioBase.ToString()); 33: }
34:
35: Console.WriteLine("salário ganho: " + empregadoAtual.Salario() + "\n"); 36: }
37:
38: for (int i = 0; i < empregados.Length; i++)
39: Console.WriteLine("Empregado " + i.ToString() + " é um " + empregados[i].GetType()); 40:
41: Console.ReadLine();
42: }
43: }