Mapear objetos em C

Este artigo visa passar uma visão geral de como mapear os conceitos da Orientação a Objetos para uma linguagem não orientada a objetos, utilizando como estudo de caso a linguagem C.

[ Hits: 17.288 ]

Por: Fábio Felix Dias em 29/01/2010 | Blog: http://lattes.cnpq.br/3165934037473827


Herança



A herança pode ser implementada de várias formas em uma linguagem que não possui a abordagem orientada a objetos. Podem ser destacadas:
  • Hierarquia de classes horizontalizada: expandir cada classe concreta como uma estrutura independente, reimplementando cada operação herdada em cada uma delas, além de duplicar também os atributos que seriam herdados. Essa abordagem leva a duplicação de atributos e métodos que pode ser retirada através do uso de macros ou de estruturas. Os atributos herdados podem ser colocados em uma estrutura e essa pode ser introduzida nas classes concretas diminuindo a quantidade de linhas. A utilização de espaços de nomes também é bem vinda nessa implementação.
  • Criação de objetos separados: criar um objeto com os atributos que são inerentes e os demais objetos devem possuir uma referencia para aquele. Com esses atributos dentro de um só objeto pode-se criar métodos que os manipulem.
  • Evite a herança: algumas aplicações não precisa de herança e outras nem às possuem. Onde isso acontece as classes podem ser representadas por estruturas simples.

Ex.:

typedef struct objeto{
char* nome[];
char* cor[];
}Objeto;

typedef struct quadrado{
Objeto * obj;
double aresta;
}Quadrado;

typedef struct circulo{
Objeto * obj;
double raio;
}Circulo;

Resolução de métodos

Uma característica inerente é o polimorfismo, mas como fazer para C resolver os métodos em tempo de execução já que essa característica não é implementada nessa linguagem, é o foco desta sessão. Para isso, pode-se tratar a resolução de métodos de algumas formas como:
  • Métodos estáticos: se as classes já forem definidas para cada objeto, o método certo pode ser determinado antes da compilação removendo assim a necessidade de resolução. A única dificuldade é a hierarquia das classes ser modificada, mesmo assim não é difícil para o programador determinar qual a classe que deverá chamar um determinado método;
  • Métodos dinâmicos: se o programador necessita aplicar um determinado método a um conjunto heterogêneo de classes, é obvio que a resolução será necessário. O C utiliza ponteiros para métodos o que pode auxiliar na execução dinâmica dos métodos.

A ideia básica é resolver a maior quantidade possível de métodos em tempo de compilação.

Associações

Estas são mantidas da mesma maneira que em linguagens OO com a utilização de ponteiros ou referencias. 1x1, um ponteiro em um dos lados da associação ou em ambos a depender da necessidade de visualização; 1xn, utilização de um ponteiro para uma estrutura de dados, contendo as estruturas que participam n fezes, no lado que participa uma vez da associação. É interessante criar métodos que encapsulem as operações de manipulação de ponteiros para uma maior segurança.

Concorrência

A grande maioria das linguagens de programação não possuem suporte nativo ao controle de concorrência, em C não seria diferente. Mesmo assim, pode-se utilizar chamadas ao kernel dos sistemas ou bibliotecas criadas para essa finalidade como a OpenMP, Pthread etc.

Encapsulamento

Com uma das principais características das linguagens OO é difícil de ser portada para as linguagens não orientadas. Seguindo alguns passos pode-se amenizar essa deficiência:
  • Evitar utilização de variáveis globais;
  • Escrever os métodos de cada classe em arquivos separados;
  • Incluir estruturas que sejam realmente utilizadas;
  • Não acessar os campos diretamente.

Referências

RUMBAUGH, James. BLAHA, Michael. Modelagem e Projetos Baseados em objetos. São Paulo: Campus, 1994.

SEBESTA, Robert W. Conceitos de Linguagens de Programação. trad. José Carlos B. Santos. 5. ed. Porto Alegre: Bookman, 2003.

Página anterior    

Páginas do artigo
   1. Introdução
   2. Herança
Outros artigos deste autor
Nenhum artigo encontrado.
Leitura recomendada

Tratamento de exceções na linguagem C

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

Bug afeta todas as distros

openCertiface: Biométrica Facial em nuvem baseada em software livre

Desenvolvendo aplicativo para autenticação biométrica utilizando a Libfprint

  
Comentários
[1] Comentário enviado por upc0d3 em 29/01/2010 - 21:17h

Deus vou fingir que nao li esse artigo !

Quer usar OO em C ?
Pq sera que tem C++ entao neh ?

Jah ouviu a expressao "cada macaco no seu galho" ?


[2] Comentário enviado por f_Candido em 29/01/2010 - 22:19h

Olá,
É interessante quando se aprende um novo paradigma, fazer associações com outros paradigmas. No entanto, o paradigma OO, é uma outra forma de pensar, uma outra forma de não somente escrever softwares, mas outra forma de elabora-los.
Enfim, Abraços.

[3] Comentário enviado por georgekihoma em 29/01/2010 - 22:21h

Cara, meus parabéns. Há um tempo atrás eu teimei com alguns colegas que esse tipo de abordagem não seria possível. Na época eles me provaram o contrário. Mas achei que era uma dúvida minha e desses colegas. Realmente seu artigo é nota 10. E realmente o que é OO?
Acho que seu artigo vai nessa linha de questionamento. Parabéns de novo.
Sobre o comentário do camikase, faz de conta que é apenas um ponteiro de conteúdo NULL.

[4] Comentário enviado por brunojbpereira em 29/01/2010 - 23:06h

Eu estava discutindo isso no trabalho uma vez, e este artigo é uma prova da minha opinião, que dá para disassociar paradigmas das linguagens de programação. Parabéns pelo artigo.

[5] Comentário enviado por upc0d3 em 29/01/2010 - 23:20h

Aff... "ponteiro de conteudo NULL", muito bem entao !

1. "Transformação de classes em structs"

Esquece, classe e estruturas sao coisas diferentes. Por exemplo, nao posso implementar modificadores de acesso em estruturas, eh tudo global na estrutura. Para o "georgekihoma", va ler sobre classes!

2. "Alocação de memória"
Ex.:

Criação:

Desenho* desenho = malloc(sizeof(Desenho));

Outro motivo de porque classes sao diferentes de estruturas !

3. "reimplementando cada operação herdada em cada uma delas, além de duplicar também os atributos que seriam herdados."

Cago aqui tbm, Heranca EVITA duplicacao de codigo, ou seja, NAO EH OO !

4. "Resolução de métodos"

Como eh que tu vai sobrecarregar os metodos ? Nao da para fazer em C... NAO EH OO !

5. "Concorrência"

O que exatamente tu entende por concorrencia ?
E o que ela tem exatamente a ver com OO ?

"A grande maioria das linguagens de programação não possuem suporte nativo ao controle de concorrência, em C não seria diferente."

Mas eh obvio que sim. Concorrencia eh implementado pelo SO !

6. "Encapsulamento"
Nao tem encapsulamento. NAO EH OO !

Essencialmente, OO esconde os podres das linguagens estruturadas/imperativas

======================================
Parem de misturar coisas que nao DEVEM ser misturadas !

[6] Comentário enviado por f_Candido em 29/01/2010 - 23:31h

Calma Rapaz... Realmente, acredito que o foco do artigo seja demonstrar uma forma(leia-se gambiarra), de implementar conceitos de OO(como o colega acima não sabe - Orientação a Objetos) em uma linguagem estruturada. Acredito que seja comum a principiantes associar struts com Classes, isso é fato, é natural.
Em relação a Concorrência, não entendi de onde ele tirou isso... Acredito que não seja da bibliografia citada.
Definitivamente, OO é uma forma de pensar, e estruturado é outra. Mas vale lembrar, nenhum paradigma é perfeito. E outro erro crasso é associar paradigma com linguagens. Isso não existe. Não se apeguem a tecnologias.

Abraços

[7] Comentário enviado por octopos em 30/01/2010 - 03:36h

Ao camikase:

1º É de extrema importância esse tipo de conhecimento, pois:
- Se fosse algum fizer ou ter feito a construção de um compilador, vc poderá implementar outros paradigmas a partir da linguagem usada na construção.
- A construção de sistemas operacionais se dão em maior parte usando C, e conceitos de O.O , recomendo-lhe a ler um pouco do código fonte do kernel Linux

2º Classes são diferente de estruturas, claro! Mas são com elas pode-se implementar estruturas de dados com politicas de acesso, e vale lembrar que classes são alocadas dinamicamente assim como o amigo usou, não é pq vc não vê que não acontece. Na verdade o conceito de classe é muuito similar ao de uma estruturas, podendo sim existir métodos dentro de uma estrutura, bastando ponteiros void apontando para funções ( http://theory.uwinnipeg.ca/programming/node87.html ).

3º Assim como é possível declarar ponteiros para void dentro de uma struct, é possível declarar ponteiros para estruturas, assim como o amigo usou, fazendo sim a existência de herança primitiva, com resolução de escopo manual.
Você pode ver esse tipo de trick e muuuitos outros aqui http://lxr.free-electrons.com/source/kernel/cpu.c?v=2.6.33-rc5 .

4º É possível sim haver sobrecarga de métodos, na verdade os "métodos" nem precisam ter seus argumentos tipados! Mais uma vez se analizar o código do kernel Linux vai ver muuuitas funções com parâmetros não tipados, e alguns tricks para o compilador aceitar e usar os endereços certos em tempo de execução.

5º . Na verdade concorrência não tem haver diretamente com O.O, mas o autor apenas quis mostrar 2 alternativas de concorrência que SÃO USERLAND, vamos lá, tanto OpenMP e Pthread são tratados por libs acima da API do kernel. Isso é, provavelmente no ambiente aonde você irá rodar esses códigos serão relacionados a UMA kernel thread, isso é N user thread ligadas a uma kthread!

Portanto o escalonador verá todas essas threads como um único work, e irá escalona-los como tal. E quem trata o escalonamento das user thread é justamente a lib! Então não tem nada haver com o S.O diretamente!

6º. O que você chama de encapsulamento? Pra mim acessar uma série de valores e endereços de memória através de um apontador é encapsulamento o suficiente! Você pode acessar o que colocar dentro de uma struct apenas sabendo o seu endereço, com o apontador!!

Oo

E um recado pessoal.... não critique aquilo que conhece, pega mal...
Ok?

=]

[8] Comentário enviado por f_Candido em 30/01/2010 - 08:01h

Olá,
Agora fiquei curioso :

Octopos diz : "A construção de sistemas operacionais se dão em maior parte usando C, e conceitos de O.O , recomendo-lhe a ler um pouco do código fonte do kernel Linux"
Que grande parte dos SO são implementados usando C, isso é fato, e também que são usados conceitos OO, mas minha dúvida reside no fato de que, este conceitos são usados com C, ou com outra linguagem que suporte nativamente OO?
Octopos diz : "O que você chama de encapsulamento? Pra mim acessar uma série de valores e endereços de memória através de um apontador é encapsulamento o suficiente! Você pode acessar o que colocar dentro de uma struct apenas sabendo o seu endereço, com o apontador!!"
Muitas pessoas não conseguem separar conceitos de implementações. Como o colega disse, Encapsulamento, está mais relacionado com abstração do problema, não devemos associar com modificadores de acesso, não mesmo.

Abraços a todos

[9] Comentário enviado por slack felix em 30/01/2010 - 18:31h

1. A inteção do artigo não é fazer ninguem largar C++, Java ou qualquer outra linguagem
OO para programar esse paradigma em C, seria quase que uma burrice fazer isso se o cabra
pudesse escolher entre uma ou outra visão.

2. Algumas características são básicas para uma linguagem que suporte OO como, "tipos
de dados abstratos, herança, e um tipo particular de vinculação dinâmica" (SEBESTA).
Baseados nisso, podesse implementar tambem o encapsulamento e à herança e outros
conceitos necessários. Se alguem quizer dar uma olhada no livro de James Rumbaugh, vai
perceber que eu segui a mesma estrutura com todos os tópicos que ele relaciona.
Particularmente, eu não penso que tudo que ele colocou é necessário ou essencial para OO,
ou, na verdade, até mesmo são idéias que podem ser relacionadas com qualquer linguagem,
mas para seguir a mesma lógica desse autor deixei os mesmos tópicos.

3. Na verdade, o que alguns disseram, o interessante é ver que as técnicas independem
da linguagem na qual elas estejam sendo implementadas. Claro, existem linguagens onde
certas técnicas são mais facilmente implementadas e outras onde as coisas funcionem
como uma "gambiarra". Mas, mesmo uma linguagem não implementando certos conceitos não
quer dizer que eles não possam ser utilizados pelo programador de alguma forma. Não
podemos ficar BITOLADOS na idéia de que na linguagem tal não dá pra fazer isso, ou aquilo
porque ela não suporta, mas sim SE FOR NECESSÁRIO E NÃO EXISTIR OUTRA FORMA É
CLARO, buscar as melhores formas de usar as melhores abordagens mesmo onde parece não
dar pra fazer, ou onde ninguem fez ainda, ou não é usual fazer.

4. MEU ERRO PRINCIPAL, foi não especificar na introdução ou na descrição do artigo que o
exposto nele deveria ser alvo de discussão de: se podemos ou não implementar os conceitos de
OO ou qualquer outro em linguagens que não os suportem.

[10] Comentário enviado por octopos em 30/01/2010 - 21:41h

Olá f_Candido

Esses conceitos são usados em ANSI C mesmo, dei exemplo do kernel Linux pq é o que tenho mais "familiaridade", um exemplo de que o autor disse, qnd precisasse resolver o problema e não outra solução.

Eu disse não somente de modificadores de acesso, mas principalmente de abstração. Abstração de uma estrutura de dados ser contêiner de vários outros objetos, entenda-se como endereçamentos na heap e valores direcionados para o stack do processo, e poder passar isso da forma que quiser! Como um objeto de uma classe correto?
Na verdade, é possível em tempo de execução dizer que aquilo que uma função recebe ou *retorna* é uma determinada struct!

Um exemplo simples, além de largamente usado no kernel Linux, é a criação de linguagens orientadas a objeto através de linguagens procedurais ou o nome que quiser dar.
Na construção de um compilador é possível fazer esse tipo de associação semântica.... de forma que literalmente o uso de structs torna possível a criação de classes, objetos, heranças etcs, etcs ...
É disso que eu chamei de encapsulamento, por isso que perguntei "O que você chama de encapsulamento?" pois tinha certeza que ele pensava em alto nível. Não que tenha o certo ou errado disso, eu só expus o que eu entendia como encapsulamento e perguntei o que ele quis dizer.
É questão de sintática e semântica, em bibliografias encontrasse controvérsias, principalmente entre engenharia de software e sistemas operacionais... =P

Abrs =]


[11] Comentário enviado por f_Candido em 30/01/2010 - 23:11h

Sim, entendi, pensei que os conceitos OO eram implementados em C++. Excelente observação. Em relação a construção de compiladores, realmente havia esquecido este detalhe. Na disciplina em que cursei, onde construímos um compilador, ou melhor um interpretador, tudo se resolvia no sintático e semântico. Infelizmente no semântico somente trabalhamos com tipos...

Agradeço o esclarecimento.

Abraços e Até

[12] Comentário enviado por franciscosouza em 31/01/2010 - 11:46h

Só adicionando mais um exemplo, a implementação padrão de Python, chamada CPython, é feita em C e de forma orientada a objetos :)

Como o Felix deixou bem claro, é uma alternativa quando não existir alternativas :)

[13] Comentário enviado por ravishi em 03/03/2010 - 10:33h

Parabéns pelo artigo. Muito útil. Para quem se interessar pelo assunto, há um ótimo texto escrito muito antes das linguagens "modernas" (Ruby, Python, PHP, etc) se tornarem populares: http://www.planetpdf.com/codecuts/pdfs/ooc.pdf. O autor utiliza C para implementar orientação a objetos de uma maneira bem completa. Vale a pena checar.

[14] Comentário enviado por thiagova em 30/04/2010 - 13:16h

Como alguns já comentaram, estranho mesmo dar de cara com este artigo.
Normalmente, usa-se C e suas struct´s para que se possa, logo mais, abordar o tema super importante na programação (a OO).
Me estranha muito, que talvez alguém possa ter iniciado os seus estudos de linguagem já abordando este assunto (OO).
Porém, nunca é de mais, darmos uma boa olhada em struct, functions, procedures, etc... não fossem essas estruturas, o OO provavelmente seria algo bem distante no futuro (se trabalhar com alguma delas, notará que OO só tem conceitos que o complementa, mas não está longe do que o foram estas outras estruturas).

[15] Comentário enviado por jota.santos em 01/05/2010 - 12:33h

Cara Parabéns pelo Material! o que voce abordou foi como usar um pouco da filosofia OO em C e não como programar OO em C, mas isso é bom! claro que em um projeto que uma linguagem de paradigma OO se encaixe melhor que C, não iremos usar C e adaptações que simule um OO, mas em um projeto que seja desenvolvido em C isso é muito bom! como o exemplo do amigo franciscosouza deu acima. cada linguagem tem sua especificação e sua especialidade C é muito poderosa tanto é que varias API e varios OS são desenvolvido em C. então pessoal tudo isso é válido!


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts