A mágica do polimorfismo e seus conceitos na ótica de C/C++

llg

Linkagem Dinâmica x Linkagem Estática? Quais os tipos de polimorfismo? Overhiding ou Overloading? Como C/C++ proporciona a linkagem dinâmica? Método da tabela virtual?

[ Hits: 18.246 ]

Por: Lucas Lira Gomes em 30/11/2010 | Blog: http://lucasrefuge.blogspot.com/


Introdução



Polimorfismo em OOP se resume a habilidade que um operador, função ou função membro (o pessoal de Java costuma chamar de método, aqui eu faço uso da nomenclatura utilizada Bjarne Stroustrup) possuem de agir de maneira diferente em contextos distintos.

Podemos fazer coisas como chamar diferentes funções através de um único tipo de chamada de função. Não pretendo neste artigo porém, introduzir a noção de polimorfismo à iniciantes, trate-se mais de uma exposição de conceitos fundamentais, embora pouco explorados por quem trata do assunto.

Por fim faço uma síntese de como C/C++ permite o polimorfismo advindo de uma hierarquia de herança e no que este polimorfismo, em especifico, implica.

Linkagem Dinâmica x Linkagem Estática

Há dois termos que são normalmente usados quando se discute polimorfismo em linguagens de programação orientada a objeto: linkagem estática e linkagem dinâmica. Em C/C++, referem-se à quando os tipos envolvidos podem ser resolvidos em tempo de compilação e em tempo de execução respectivamente.

Na linkagem estática, o compilador é feito de forma a poder resolver os tipos envolvidos de forma segura, sem a necessidade de manter qualquer estrutura em tempo de execução. Podemos ver isso quando temos um ponteiro que pode acessar uma função membro, se isso é possível certamente o objeto referenciado pelo ponteiro também pode acessar a mesma função membro, desde que o objeto referenciado seja coerente com o tipo do ponteiro. Portanto podemos determinar em tempo de compilação, qual função membro deve ser executada neste caso. Como exemplo de linkagem estática temos os argumentos padrões, templates (conhecido como polimorfismo paramétrico) etc.

Já a linkagem dinâmica se faz necessária porque há casos em que não é possível determinar se a conversão de um tipo base em um tipo derivado é "seguro", em tempo de compilação, pois os compiladores ainda não são capazes de notar a presença de erros de semântica. Pode-se ver claramente a necessidade, de que se mantenha então, estruturas em tempo de execução, que tenham a capacidade de garantir essa "segurança".

O objetivo principal da linkagem dinâmica é suportar uma interface comum, enquanto permite que vários objetos que utilizam essa interface definam suas próprias implementações. Em C/C++ a linkagem dinâmica é consequência direta do uso de funções virtuais e de herança.

Os tipos de polimorfismo

Existem basicamente dois grandes grupos de polimorfismo e entende-los pode ajudar a diferenciar melhor o que é linkagem dinâmica do que é linkagem estática nos mais diferentes contextos:
  • Polimorfismo Puro
  • Polimorfismo Ad-Hoc

O polimorfismo puro compreende o conceito de overhiding e o polimorfismo Ad-Hoc compreende o conceito de overloading (ou sobrecarga) e funções virtuais.

Overloading representa a implementação do polimorfismo estático (que faz uso de linkagem estática), que se caracteriza principalmente por operadores ou funções que possuem o mesmo nome (o que não implica numa interface em comum), mas que podem realizar diferentes tarefas para diferentes contextos.

Podemos ter aqui várias funções com o mesmo nome, mas com números e tipos de argumento diferentes.. Por exemplo, você pode usar uma função para somar dois inteiros assim como uma para somar dois floats, ambas poderiam ter o mesmo nome, o que mudaria seriam os tipos dos argumentos, mas você ainda teria uma função que pode se comportar de forma diferente de acordo com o contexto.

Enquanto que a concepção de Overhiding é aplicada para o polimorfismo dinâmico (que faz uso da linkagem dinâmica), onde ainda temos funções membro (que serão as funções membro virtuais) com o mesmo nome, mas o que irá ser feito é definido apenas em tempo de execução de acordo com o tipo de objeto que foi referenciado, sendo portanto uma consequência direta do uso de herança. Aqui temos uma completa substituição de uma função para outra independente dos tipos ou quantidade de argumentos.

Como exemplo, poderíamos ter uma classe base que implementa uma função e uma classe derivada que muda o comportamento da função, o que irá acontecer na execução do programa depende apenas do tipo do objeto.

    Próxima página

Páginas do artigo
   1. Introdução
   2. Como C/C++ proporciona a linkagem dinâmica
Outros artigos deste autor

Uma análise do software livre e de sua história

Leitura recomendada

Linguagem C - Funções Variádicas

Tratamento de exceções na linguagem C

Bug afeta todas as distros

Sinais em Linux

Como funcionam os alocadores de memória do STD C?

  
Comentários
[1] Comentário enviado por removido em 30/11/2010 - 20:13h

rapaz, que título, que título!!!...

[2] Comentário enviado por llg em 30/11/2010 - 20:20h

Hauhauahua, e o artigo?

[3] Comentário enviado por aleaugustoplus em 01/12/2010 - 14:06h

Esse é um dos motivos do JAVA ser mais lento que o C/C++ pois em JAVA todas a chamadas de funções são naturalmente decididas em tempo de execução.

[4] Comentário enviado por llg em 01/12/2010 - 15:23h

Hum, interessante. Não sabia que JAVA tratava todas as chamadas de funções dessa forma. Vivendo e aprendendo XD.

[5] Comentário enviado por altairmsouza em 01/12/2010 - 15:57h

llg (Lucas),

Parabens em tratar de OO com C/C++, contudo acredito que iria enriquecer mais o artigo com exemplos em forma de codigo fonte com os dois tipos de polimorfismo.

[6] Comentário enviado por llg em 01/12/2010 - 16:41h

Hum, vou fazer disso uma prática mais frequente. No meu próximo artigo que será sobre funções virtuais já estou colocando os códigos.

[7] Comentário enviado por robsoncassol em 03/12/2010 - 14:16h

Gostei do artigo esta bem escrito e suscito.

Mas discordo quando você trata o overloading como polimorfismo, pois neste caso a unica coisa que é igual nas funções são os nomes.
Já no caso do overhiding um método com a mesma assinatura pode apresentar vários comportamentos, fazendo jus ao nome "polimorfismo".
De qualquer forma é tudo questão de nomenclatura, o que importa é o conceito da coisa. E isso esta bem claro no artigo.

valeu.

[8] Comentário enviado por Teixeira em 05/12/2010 - 18:27h

O artigo está bom, assim com aquele gostinho de "quero mais".

[9] Comentário enviado por llg em 05/12/2010 - 19:16h

@robsoncassol: Obrigado ^^. Mas acho que houve algum desentendimento. O overhiding é realmente polimorfismo, só que é dinâmico(aka tempo de execução). Ele costuma aparecer quando criamos uma hierarquia de classes, por exemplo, e usamos um ponteiro da classe base para referenciar algum objeto pertecente a um ramo inferior da hierarquia. Esse método permite que vocẽ desenvolva código que pode funcionar de formas diferentes, executando tarefas diferentes, em objetos de classes diferentes, desde que descendentes da mesma classe base. Não sei se solucionei o caso, mas a questão da assinatura ser semelhante (no polimorfismo estático não é possível ser completamente igual senão o compilador encara como redefinição) depende apenas do progamador, tanto no polimorfismo estático quanto no dinâmico é possível fazer com que se tenha operadores diferentes, por exemplo, e mesmo assim ainda seria considerado polimorfismo, não é so uma questão de nomenclatura não, é o conceito da coisa XD.

@Teixeira: Obrigado ^^. Em breve sairá um de "Funções Virtuais e Controle de Acesso" em C/C++, se a linguagem lhe interessar garanto que irá gostar XD.

Atenciosamente, Lucas Lira Gomes

[10] Comentário enviado por robsoncassol em 06/12/2010 - 09:54h

Hum, foi mal, eu havia invertido os nomes. Mas a idéia é a mesma.

Concordo com "O overhiding é realmente polimorfismo"

O problema é tratar o overloading como "Polimorfismo estático". Pois, como vc mesmo descreveu, são apenas métodos parecidos não existe comportamento polimórfico.

[11] Comentário enviado por llg em 06/12/2010 - 21:04h

@robsoncassol : Bem, polimorfismo estático ainda continua sendo polimorfismo.

Pense em operator overloading, por exemplo, que nada mais é do que vocẽ fazer os operadores da linguagem ter determinado comportantamento em uma classe sua. É um polimorfismo pois você deu ao operador x a capacidade (que ele geralmente não teria) de fazer algo diferente, ele tem um comportamento novo para essa classe específica. Note que nem todas as linguagens dispoêm de uma ferramenta tão poderosa como operator overloading ( C/C++ rlz ;}). Perceba também, que C não permitiria que você tivesse uma função com o mesmo nome, mesmo que tivesse argumentos diferentes (pois ele encararia isso como redefinição de função), mas em C/C++ se você tiver argumentos diferentes ele aceita porque C/C++ da suporte a polimorfismo (no caso, estático). Você poderia ter uma função que soma inteiros e outra que soma floats, mas com o mesmo nome, essa função tem comportamento polimorfico pois ela sabe trabalhar com inteiros e floats, cada um a sua maneira. Todas as funcionalidades que citei podem ser resolvidas em tempo de compilação XD!!!

Espero que tenha solucionado qualquer dúvida.

Atenciosamente, Lucas Lira Gomes


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts