Ponteiro em C: Polimorfismo

funções X macros compilação condicional Diagnóstico

Muito se discute a respeito das facilidades criadas com a utilização de linguagens orientadas a objetos (OO), principalmente quando a comparação é realizada com a linguagem C. De fato, a linguagem C não possui as características de uma linguagem OO, contudo alguns desses aspectos podem ser criados em C. É claro que isto exige empenho por parte do programador. Nesse contexto, este artigo tem o objetivo de apresentar uma forma de implementar os principais conceitos de OO: Herança, Encapsulamento e Polimorfismo. O aprofundamento dos tópicos não será apresentado neste artigo, pois o objetivo é demonstrar a utilização dos ponteiros e suas aplicações!

Aspectos de Orientação a Objeto

Como apresentado na introdução, Herança, Encapsulamento e Polimorfismo são conceitos básicos de OO. O encapsulamento já foi discutido no artigo anterior em que os tipos de dados abstratos (TDA) eram criados de forma que sua implementação não era conhecida. Diante disso, um TDA é considerado como uma classe em OO, pois tem como função representar uma estrutura geral e as suas operações. Esse aspecto permite modularizar um código, isto é, organizá-lo em unidades funcionais distintas. Neste ponto, dois tópicos são essenciais: Herança e Polimorfismo.

  • Herança – Uma característica importante da POO é permitir a criação de novas classes a partir de uma classe já existente. Essa característica pode ser entendida como uma especialização, isto é, uma forma de ampliar a funcionalidade de uma classe;
  • Polimorfismo – A palavra polimorfismo significa ‘de muitas formas’. Na POO isso significa que a partir de um mesmo nome, que representa um objeto ou método, podemos ter várias formas, isto é, comportamentos diferentes.

Quando a herança é utilizada temos uma relação hierárquica. A classe que foi herdada é chamada de classe base, já a outra classe é chamada de derivada. Nesse contexto, a classe derivada herda de uma classe base todos os métodos, campos, propriedades e eventos da classe base. Dependendo da forma como isso foi especificado, é possível definir alguns elementos que podem ser alterados pela classe derivada! Considere o exemplo clássico [2] de formas geométricas mostrado na Figura 1.

Generalização e Especialização - Polimorfismo
Figura 1: Generalização e Especialização

A classe Shape define um conjunto de atributos e um método chamado Draw. Note que na declaração do método Draw aparece a keyword ‘virtual’. Essa keyword especifica que o método pode ser substituído em uma classe derivada. Na implementação mostrada abaixo optou-se pela linguagem C#.

Abaixo são mostradas as classes derivadas da classe Shape. Observe que nas classes Circle, Rectangle e Triangle o método Draw aparece com a keyword ‘override’, indicando a substituição do método da classe base pelo método da classe derivada. Além disso, todas essas classes podem acessar os atributos de Shape: X, Y, Height e Width.

O potencial deste tipo de implementação pode ser observado no código abaixo. Considere que existe uma estrutura de dados do tipo Shape, ou seja, da classe base. Essa estrutura de dados é populada com objetos do tipo Rectangle, Triangle e Circle. Esse procedimento é possível, pois essas classes também são do tipo Shape. No processo iterativo 'foreach' essa estrutura de dados é percorrida e, para cada iteração, o método Draw definido em Shape é invocado.

À primeira vista, o método Draw em Shape será executado, contudo esses métodos foram estendidos. Portanto, ao chamar o método Draw a partir de Shape, o método será executado na classe derivada! Assim, cada classe derivada apresentou um comportamento diferente, porém a chamada pôde ser realizada a partir de um nome comum.

Polimorfismo e Funções Virtuais em C

A forma mais simples de criar um mecanismo de herança e polimorfismo em C é a partir das tabelas de funções virtuais, também chamada de VTable. Uma VTable consiste de um conjunto de ponteiros para funções que são comuns nas classes derivadas e que são agrupados em uma struct. Considere, por exemplo, a classe Shape e o método virtual Draw na linguagem C.

Diante disso, as classes derivadas tem o dever de atribuir aos ponteiros de funções conforme suas implementações. A definição de Rectangle, Triangle e Circle são mostradas abaixo.

Note que na definição dessas estruturas a base Shape é sempre o primeiro membro. Organizando desse modo fica fácil observar a herança e que o endereço base é o endereço da estrutura shape. Dito de outra maneira, essas estruturas apresentam a relação de extensão. A Figura 2 ilustra essa situação.

Disposição das estruturas na memória - Polimorfismo
Figura 2: Disposição das estruturas na memória

Cabe ressaltar que esse tipo de construção é possível somente porque a descrição da estrutura Shape é conhecida, caso contrário seria necessário utilizar um ponteiro para estrutura Shape. Um breve exemplo, sem considerar os módulos e construtores para cada classe derivada, ilustrando a utilização das estruturas é mostrado abaixo.

Conclusão

Esse artigo apresentou, de maneira introdutória, alguns conceitos de orientação a objetos que podem ser aplicados em projetos utilizando linguagem C. Com base nesse e no artigo anterior você, leitor, poderá explorar novas formas de estruturar um projeto. Os conceitos envolvidos e demonstrados são muito importantes para reutilização de código. Outro ponto que pode ser observado é em relação à extensão e manutenção do projeto, pois a herança e o polimorfismo podem tornar o design flexível. Durante o projeto, vale a pena considerar os seguintes tópicos:

  • Programe para uma interface;
  • Encapsule o que varia;
  • Para reduzir o acoplamento das estruturas dê prioridade à composição em relação à herança.

Para saber mais

Embora o objetivo seja a implementação das técnicas de OO em C, é extremamente importante conhecer as características de orientação a objetos. Vale a pena conferir o artigo do Felipe Lavratti sobre polimorfismo em que o tópico é demonstrado com mais detalhes de modularização.

Referências

[1] – Livro: C, completo e total – 3ª edição revista e atualizada. Herbert Schildt.

[2] – https://msdn.microsoft.com/pt-br/library/ms173152.aspx

Outros artigos da série

<< Ponteiro em C: Tipo de Dado Abstrato
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Software » Ponteiro em C: Polimorfismo
Talvez você goste:
Comentários:

4
Deixe um comentário

avatar
2 Comentários
2 Respostas
0 Seguidores
 
Discussão de maior alcance
Discussão mais quente
3 Autores de comentários
Fernando Deluno GarciaCesar JuniorRafael Gebert Comentários recentes
  Notificações  
recentes antigos mais votados
Notificar
Cesar Junior
Visitante
Cesar Junior

Parabéns pelo artigo! Muito bom.

Fernando Deluno Garcia
Visitante
Fernando Deluno Garcia

Obrigado, Cesar.

Rafael Gebert
Visitante
Rafael Gebert

Excelente artigo Fernando! Nota 10!
Apenas gostaria de acrescentar aos demais leitores que o Shape * shapes[3] não precisa ser de tamanho fixo. Se implementar em forma de lista encadeada (ao invés de array) é possível alocar quantos objetos quiserem até acabar a memória. A base da minha gfx é exatame isso.
Quem sabe fica de sugestão para mais um artigo de ponteiros, hein Fernando?

Fernando Deluno Garcia
Visitante
Fernando Deluno Garcia

Olá, Rafael.

Um artigo sobre listas encadeadas? Pode ser uma série sobre estrutura de dados. É um assunto interessante!

Obrigado pelo retorno!

Séries



Outros da Série

Menu