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
Comentários:
Notificações
Notificar
guest
4 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Cesar Junior
Cesar Junior
20/01/2016 08:11

Parabéns pelo artigo! Muito bom.

Fernando Deluno Garcia
Fernando Deluno Garcia
Reply to  Cesar Junior
20/01/2016 13:51

Obrigado, Cesar.

Rafael Gebert
Rafael Gebert
19/01/2016 13:44

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
Fernando Deluno Garcia
Reply to  Rafael Gebert
20/01/2016 13:51

Olá, Rafael.

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

Obrigado pelo retorno!

Talvez você goste:

Séries



Outros da Série

Menu

WEBINAR
 
Porque o RTOS não faz o que eu quero?

Data: 28/10 às 19:30h - Apoio: Mouser Electronics
 
INSCREVA-SE AGORA »



 
close-link