Anda di halaman 1dari 4

Polimorfismo em Delphi

http://www2.unoeste.br/~ aglae/ling_pro/delphi_polimorfismo.htm

POLIMORFISMO EM DELPHI
Mtodos Virtuais e Dinmicos
As funes e os procedimentos Pascal usualmente baseiam-se na ligao esttica (static binding). Isto significa que uma chamada de mtodo resolvida pelo compilador e pelo linkeditor. Eles substituem a chamada por uma chamada localizao de memria especfica em que a funo ou procedimento reside (a qual conhecida como endereo da funo). As linguagens de programao orientadas a objeto, inclusive Object Pascal, permitem o uso de outra forma de ligao, conhecida como ligao dinmica ou ligao tardia. Neste caso, o endereo de fato do mtodo a ser chamado determindo em tempo de execuo. A vantagem desta abordagem conhecida como polimorfismo. Suponha que uma classe e uma subclasse (digamos, Animal e Cao) definam ambas um mtodo, e que este mtodo tenha uma ligao dinmica. Agora voc pode aplicar este mtodo a uma varivel genrica, como, por exemplo, MeuAnimal, a qual, em tempo de execuo, pode referir-se a um objeto da classe Animal ou a um objeto da classe Cao. Neste caso, o mtodo real para chamar determinado em tempo de execuo dependendo da classe do objeto atual. A idia bsica do polimorfismo que voc escreve a chamada a um mtodo, mas o cdigo chamado de fato depende do tipo do objeto, o qual pode ser determinado somente em tempo de execuo por causa da regra de compatibilidade de tipos. O exemplo seguinte, ANIMAIS2, amplia ANIMAIS1 e demonstra esta tcnica. Na nova verso do exemplo, as classes Animal e Cao tm um novo mtodo, Verse (para obter o som emitido pelo animal selecionado). Este mtodo definido como virtual na definio da funo Animal e posteriormente anulado (ignorado) na definio da classe Cao. Isto levado a efeito pelo uso das palavras-chave override e virtual:
Type Animal = class public constructor Create; function GetTipo: string; function Verse: string; virtual; private Tipo: string; End; Cao = class (Animal) public constructor Create; function Verse : string; override; end;

Obviamente, os dois mtodos dever ser implementados. Eis uma abordagem simples:
function Animal.Verse: string; begin Verse := 'Rudo do animal'; end; function Cao.Verse: string; begin Verse := 'Au Au'; end;

Agora, qual o efeito desta chamada se voc escrever o cdigo a seguir? MeuAnimal.Verse;

1 de 4

23/6/2010 09:52

Polimorfismo em Delphi

http://www2.unoeste.br/~ aglae/ling_pro/delphi_polimorfismo.htm

Depende. Se a varivel MeuAnimal atualmente referir-se a um objeto da classe Animal, ela chamar o mtodo Animal.Verse (atalho para indicar o mtodo Verse da classe Animal). Se ela se referir a um objeto da classe Cao chamar, em vez disso, o mtodo Cao.Verse. Isto acontece somente porque a funo virtual, deste modo, tem uma ligao dinmica. A chamada a MeuAnimal.Verse funcionar para uma instncia de objeto de qualquer descendente da classe Animal, at mesmo classes que sejam definidas depois ou fora do escopo desta chamada de mtodo. O compilador no precisa conhecer todas as descendentes a fim de tornar a chamada compatvel com elas; somente a classe ancestral bsica necessria. Em outras palavras, esta chamada a MeuAnimal.Verse compatvel com todas as classes Animal futuras que ainda no criamos. Esta razo tcnica fundamental que leva a pressuposio de que as linguagens de programao orientadas a objeto favorecem a reusabilidade. Voc pode escrever algum cdigo que use as classes de uma hierarquia sem nenhum conhecimento das classes reais da prpria hierarquia. Em outras palavras, a hierarquia - e o programa - ainda extensvel, mesmo quando voc tiver escrito milhares de linhas de cdigo utilizando-a. Obviamente, h uma condio: as classes ancestrais da hierarquia precisam ser projetadas muito cuidadosamente. O programa Delphi utilizado para demonstrar a utilizao dessas novas classes possui um formulrio similar ao do exemplo anterior. Dessa vez, o boto possui a legenda Verse, e um novo nome interno (VerseButton). O nome do rtulo torna-se VerseLabel. Esse cdigo executado dando-se um clique no boto:
procedure TFormAnimals.VerseButtonClick(Sender: Tobject); begin VerseLabel.Caption := MeuAnimal.Verse; end;

Em ANIMAIS1, havia uma chamada a uma funo, GetTipo, a qual simplesmente retornava o valor de um campo. Em ANIMAIS2, h uma nica chamada, MeuAnimal.Verse, que as vezes refere-se a um mtodo de uma classe e outras vezes refere-se a um mtodo de outra classe. Esta uma tcnica interessante e poderosa. O mesmo cdigo compilado chama uma de duas funes, dependendo do tipo real de um objeto em tempo de execuo. Para apreciar isto plenamente, considere que os dois ou mais mtodos podem ser complexos e completamente diferentes um do outro. Mtodos virtuais tambm podem ser chamados pelos mtodos da mesma classe, e eles podem chamar outros mtodos virtuais ou estticos.

Mtodos Virtuais Versus Mtodos Dinmicos


No Delphi, h basicamente duas maneiras diferentes se usar a ligao tardia com um mtodo. Voc pode declarar o mtodo como virtual, vimos anteriormente, ou declar-lo como dinmico. A sintaxe destas palavras-chave exatamente a mesma, e o resultado de seu uso tambm o mesmo. O que diferente o mecanismo interno usado pelo compilador para implementar a ligao dinmica. Os mtodos virtuais baseiam-se numa tabela de mtodos vrituais (Virtual Method Table VMT), tambm conhecida como vtable (do jargo da linguagem C++). Uma tabela de mtodos virtuais uma coleo de endereos de mtodos. Para uma chamada a um mtodo virtual, o compilador gera cdigo para pular para um endereo armazenado no ensimo slot da tabela de mtodos virtuais do objeto. O compilador determina o ndice na tabela procurando pelo tipo de objeto em tempo de execuo, geralmente armazenado como um nmero dentro do mesmo objeto. As tabelas de mtodos virtuais permitem uma rpida execuo das chamadas a mtodos. O principal inconveniente que elas exigem uma entrada para cada mtodo virtual de cada classe descendente, mesmo que o mtodo no seja anulado na classe descendente. s vezes, isto tem o efeito de propagar entradas de tabelas de mtodos virutais (at mesmo para mtodos que no so anulados) ao longo de sua hierarquia de classes. Ser necessria uma enorme quantidade de memria para armazenar o mesmo endereo de mtodo um grande nmero de vezes. As chamadas de mtodos dinmicos, por outro lado, so despachadas usando um nico cdigo

2 de 4

23/6/2010 09:52

Polimorfismo em Delphi

http://www2.unoeste.br/~ aglae/ling_pro/delphi_polimorfismo.htm

indicando o mtodo. A procura da funo correspondente geralmente mais lenta do que a pesquisa de tabela simples de um s passo dos mtodos virtuais. A vantagem que as entradas de mtodo dinmicas somente se propagam nas descendentes quando estas ignoram o mtodo. Para hierarquias de objetos grandes ou profundas, o uso de mtodos dinmicos em vez de mtodos virtuais pode resultar em significativas economias de memria e causar apenas uma mnima perda de velocidade. A partir da perspectiva do programador, a diferena entre estas duas abordagens repousa somente numa representao interna diferente e uma velocidade ou uso de memria ligeiramente diferente. Fora isto, os mtodos virtuais e dinmicos so a mesma coisa. Eis uma regra emprica geral: se o mtodo for anulado por quase todas as descendentes, torne-o virtual. Se o mtodo no for anulado muito frequentemente, mas ainda precisar de ligao tardia para obter flexibilidade, torne-o dinmico, especialmente se houver muitas classes descendentes. Se o mtodo for muito chamado (por exemplo, centenas de vezes por segundo), torne-o virtual. Caso contrrio, torne-o dinmico. Obviamente, isto pressupe que voc j tenha decidido que o mtodo deve ter uma ligao tardia. Mtodos no-virtuais so a forma mais rpida de despachar o mtodo.

Mtodos Abstratos
A palavra-chave abstract usada para declarar mtodos que estaro definitivamente somente em subclasses da classe atual. A diretriz abstract define amplamente o mtodo; ela no uma declarao forward. Se voc tentar uma definio do mtodo, o compilador reclamar. Em Object Pascal, voc pode criar instncias de classes que tm mtodos abstratos. (Note que C++ usa uma abordagem oposta. Em C++, voc no pode criar instncias de classes abstratas classes que tenham funes virtuais puras.) Se voc chamar um mtodo abstrato, o Delphi emitir um erro em tempo de execuo e encerrar seu aplicativo. Diferentemente da maioria dos erros em tempo de execuo, o erro em tempo de execuo de "Chamada ao mtodo abstrato" no suscita uma exceo que seu programa pode captar. Chamar um mtodo abstrato (um mtodo que no tem nenhuma implementao) considerado um erro grava do programador, digno de uma sada fatal.
Type AbstractClass = class Function F: integer; virtual; abstract; End;

Voc pode estar querendo saber por que haveria de querer usar mtodos abstratos. A razo reside no uso do polimorfismo. Se a classe Animal tiver o mtodo abstrato Verse, toda subclasse poder redefini-la. A vantagem que agora voc pode usar um objeto Animal genrico para referir-se a cada animal definido por uma subclasse, e invocar este mtodo. Se este mtodo no estivesse presente na interface da classe Animal, a chamada no teria sido permitida pelo compilador, o qual executa uma verificao do tipo esttico. O prximo exemplo, demonstra o uso de mtodos abstratos e algumas outras caractersiticas do polimorfismo. A parte mais interessante a definio da classe Animal, a qual inclui um mtodo abstrato virtual, Verse. Tambm importante notar que cada classe derivada ignora esta definio e adiciona um novo mtodo virtual, Comer. Quais so as implicaes destas duas diferentes abordagens? Para chamar a funo Verse, simplesmente podemos escrever o mesmo cdigo que na verso anterior do programa:
VerseLabel.Caption := MeuAnimal.Verse;

Como podemos chamar o mtodo Comer? No podemos aplic-lo a um objeto da classe Animal. A instruo:

3 de 4

23/6/2010 09:52

Polimorfismo em Delphi

http://www2.unoeste.br/~ aglae/ling_pro/delphi_polimorfismo.htm

VerseLabel.Caption := MeuAnimal.Comer;

gera o erro do compilador: " Field identifier expected" Para resolver este problema, voc pode usar RTTI para moldar o objeto Animal para um objeto Gato ou Cao, mas, sem a adequada moldagem, o programa suscitar uma exceo. Veremos um exemplo desta abordagem posteriormente, mas ela est longe de ser simples. Adicionar a definio do mtodo da classe Animal uma soluo tpica para o problema, e a presena da palavra-chave abstract favorece esta escolha. Para testar nossas trs novas classes, podemos modificar o formulrio da verso anterior ligeiramente adicionando um novo boto de rdio para o novo tipo de animal. Alm de adicionar o cdigo exigido, fizemos algumas outras mudanas. As duas verses anteriores do programa criaram um objeto de cada tipo no incio, depois atriburam os objetos existentes varivel MeuAnimal quando o usurio selecionou um dos botes de rdio. Agora somente um objeto existe em um determinado momento. O formulrio possui somente um campo privado, MeuAnimal, inicializado no mtodo OnCreate com a instruo MeuAnirnal : = Cao Create. Cada um dos manipuladores de eventos OnClick dos botes de rdio remove o objeto atual e cria um novo:
procedure TformAnimais.CaoRadioButtonClick(Sender: Tobject); begin MeuAnimal.Free; MeuAnimal := Cao.Create; end;

O Cdigo para o mtodo VerseButtonClick permanece o mesmo, ainda chamando MeuAnimal.Verse e exibindo o resultado da legenda. Quando voc executa esse programa, o rtulo exibe o som do co ou do gato, ou voc experimenta um erro de tempo de execuo que interromper sua aplicao (quando voc chama o mtodo abstrato da classe Animal).

4 de 4

23/6/2010 09:52

Anda mungkin juga menyukai