Esse artigo faz parte da revista Clube Delphi Edição 75. Clique aqui para ler todos os artigos desta edição

: 0cm; TEXT-ALIGN: left" align=left>Tal comportamento pode ser modificado para métodos virtuais e dinâmicos, através do uso das diretivas virtual e dynamic, em conjunto com a diretiva override. Assim, a chamada dos métodos passa a ativar a implementação do tipo em tempo de execução, ou seja, de acordo com o tipo da instância e não o tipo definido para a variável.

O uso de override, garante que apenas uma implementação do método exista em tempo de execução nas classes descendentes, ocultando as implementações dos ancestrais. Porém, esses métodos devem ter exatamente a mesma assinatura, ou seja, mesmo nome do método e mesmo número, ordem e tipos dos parâmetros.

As diretivas virtual e dynamic são equivalentes, sendo diferentes no sentido de que a virtual otimiza a velocidade de acesso e dynamic otimiza o tamanho do código, sendo a virtual a forma mais comum e eficiente de implementar o polimorfismo. Na Listagem 1 demonstra-se o efeito do uso dessas diretivas, através de algumas modificações na hierarquia de Funcionario.

 

Listagem 1. Definição da hierarquia de Funcionario com método virtual

type

  Funcionario = class

    function CalcularSalario: real; virtual;

  end;

  FuncionarioMensalista = class (Funcionario)

    function CalcularSalario: real; override;

  end;

  FuncionarioDiarista = class (Funcionario)

    function CalcularSalario: real; override;

  end;

 

Na Listagem 1, utiliza-se na assinatura do método CalcularSalario na classe Funcionario, a diretiva virtual, enquanto que nas classes descendentes utiliza-se a diretiva override. As implementações dos métodos continuam as mesmas.

A Listagem 2 apresenta a utilização dos métodos com a diretiva override. Pressupõe-se que os valores dos campos dos objetos tenham sido modificados entre a criação dos objetos e a execução dos serviços CalcularSalario. A Listagem 2 deve ser implementada em outra unit que não a untClasses, devendo referenciá-la.

 

Listagem 2. Chamada de métodos virtuais com override

01: var

02:   Func1: Funcionario;

03:   Func2: FuncionarioDiarista;

04: begin

05:   {Funcionario 1}

06:   Func1 := FuncionarioMensalista.Create;

07:   Func1.CalcularSalario;

08:   {Funcionario 2}

09:   Func2 := FuncionarioDiarista.Create;

10:   Func2.CalcularSalario;

11: end;

 

Durante a execução do trecho de código apresentado na Listagem 2, as chamadas de métodos nas linhas 07 e 10 ativam a implementação correspondente das classes FuncionarioMensalista e FuncionarioDiarista respectivamente. Embora o tipo de dados da variável Func1 seja Funcionario (linha 02), o objeto armazenado nela é do tipo FuncionarioMensalista (linha 06). Sendo assim, em função da diretiva override, são executadas as implementações relativas às instâncias, e não relativas ao tipo da variável, como no caso dos métodos estáticos.

Vale a pena ressaltar que, para uso da diretiva override, a assinatura dos métodos deve ser exatamente igual, pois de outra forma é apresentado um erro durante a compilação. Além disso, override somente pode ser utilizado em conjunto com virtual ou dynamic, não podendo ser utilizado em métodos estáticos.

Para casos de polimorfismo onde a assinatura do método é diferente nos seus descendentes, podem ser utilizadas duas outras diretivas: overload e reintroduce.

A diretiva overload pode ser utilizada para qualquer tipo de método, seja estático, virtual ou dinâmico. Para métodos virtuais pode-se utilizar a diretiva reintroduce em conjunto para os descendentes. Além de permitir assinaturas diferentes de um mesmo método, a diretiva overload não oculta as implementações do método nos ancestrais, estando assim disponíveis mais de uma implementação simultaneamente.

Para ativar a implementação correta, são analisados os parâmetros utilizados na chamada do método, executando assim a implementação que corresponder a esses parâmetros. Porém, para os métodos virtuais, caso seja necessário, os métodos dos ancestrais podem ser ocultados, utilizando a diretiva reintroduce.

A Listagem 3 apresenta um exemplo do uso das diretivas overload e reintroduce. 

 

Listagem 3. Hierarquia com uso de overload e reintroduce

01: type

02:   Funcionario = class

03:     {Definições existentes}

04:     public

05:       function CalcularSalario: real;

06:       function CalcularPremio: real; virtual;

07:   end;

08:   FuncionarioMensalista = class (Funcionario)

09:     {Definições existentes}

10:     public

11:       function CalcularSalario(

            pHoraExtra: real): real; overload;

12:       function CalcularPremio(

            pTaxa: real): real; reintroduce;

13:   end;

14: implementation

15: {Implementações existentes}

16: function FuncionarioMensalista.

      CalcularSalario(pHoraExtra: real): real;

17: begin

18:   result := fValorMes + pHoraExtra;

19: end;

20: function FuncionarioMensalista.

      CalcularPremio(pTaxa: real): real;

21: begin

22:   result := fValorMes * pTaxa;

23: end;

 

Nota-se a presença de uma hierarquia de classes, onde a classe Funcionario é ancestral direta de FuncionarioMensalista (linha 08). Na subclasse são alterados os métodos CalcularSalario e CalcularPremio anteriormente existentes, de forma que tenham parâmetros diferentes da classe ancestral (linhas 11 e 12). Percebe-se também, que no nível mais alto dessa hierarquia, ou seja, na classe Funcionario, o método CalcularSalario é estático (linha 05) e o método CalcularPremio é virtual (linha 06).

Na classe descendente são utilizadas as diretivas overload e reintroduce, onde o método CalcularPremio possui a diretiva reintroduce (linha 12), visto que é um método virtual e deseja-se que a implementação desse método no seu ancestral seja ocultada, ou seja, não disponível nessa classe nem em seus descendentes. ...

Quer ler esse conteúdo completo? Tenha acesso completo