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.625 ]

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


Como C/C++ proporciona a linkagem dinâmica



A maioria dos compiladores modernos de C/C++ permitem o overhiding de funções através das funções membro virtuais (ou funções virtuais). O modo de proporcionar as funções virtuais é comumente conhecido como método da tabela virtual, e é inclusive usado por outras linguagens tais como D, C#, Visual BASIC e Delphi, embora estas diferentes linguagens usem terminologias diferentes para seus modos de implementar o polimorfismo dinâmico.

Geralmente o método da tabela virtual é implementado usando alguma variante da seguinte técnica: Se o objeto instanciado tem uma ou mais funções virtuais, o compilador coloca dentro do objeto um ponteiro oculto ao programador, denominado virtual-pointer, ou apenas v-pointer.

Esse v-pointer aponta para uma tabela denominada virtual-table ou v-table. O compilador cria uma v-table para cada classe que faça uso de funções virtuais, sendo que cada função virtual, tem um ponteiro que aponta para sí como elemento da tabela v-table de sua classe. A v-table de uma classe é totalmente independente da quantidade de objetos instanciados desta classe.

Na imagem abaixo temos um exemplo de uma hierarquia de herança fazendo o uso de funções virtuais para obter polimorfismo através de linkagem dinâmica:
Durante a chamada de uma função virtual, o sistema de execução deferência o v-pointer do objeto, tendo então acesso a v-table da classe na memória, então ele escolhe o elemento da v-table correspondente à função membro virtual em questão e o deferência para ir para o endereço de memória onde o código desta função membro virtual se encontra, conseguindo "gerar" o polimorfismo desejado.

Se supormos que os v-pointers são do tipo v_ptr e que as classes chamam o v-pointer de _v_pointer, poderíamos ter uma organização semelhante a descrita abaixo, com as setas representando para quem os ponteiros apontam:
A uso de v-table e v-pointers porém possui um trade-off implícito, pois seu uso trás um custo extra no tocante ao espaço usado na memória, pois é necessário um ponteiro extra, por objeto instanciado que precise de linkagem dinâmica, para representar o v-pointer e um elemento extra na v-table de cada classe, para cada função virtual desta. Além de, no mínimo, uma deferência extra, em relação as funções não-virtuais, que nada mais fazem do que "pular" para um espaço na memória pré-determinado em tempo de compilação.

Conclusão

Logo, o uso de funções virtuais possui um acesso um pouco mais devagar e gasta mais espaço na memória, embora que as CPUs modernas e o crescente aumento das memórias tenham tornado esse custo extra relativamente insignificante.

Para finalizar, podemos ver está quantidade extra de ponteiros e a presença da virtual table na figura abaixo:
Em contrapartida, sabemos que o polimorfismo proporcionado pela linkagem estática não gera overhead algum, o trabalho extra fica totalmente a cargo do compilador. A escolha de qual polimorfismo deve ser implementado depende apenas das necessidades do programador.

Bibliografia


Artigo originalmente publicado em meu blog: Pinguim Engenheiro

Página anterior    

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

Alocação dinâmica de memória em C

Desenvolvendo para microcontroladores em GNU/Linux

Dynamic libraries com libtool

OneAPI: A plataforma da Intel para facilitar o desenvolvimento com chips Intel, AMD, ARM, NVIDIA POWER e FPGA

Estudando recursividade direta e indireta

  
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