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.