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

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


Introdução



A Orientação a Objetos (OO) é o paradigma de programação mais utilizado no tempo atual para desenvolvimento de sistemas. Permite rapidez, agilidade na produção de software e a reutilização do código, evitando perda de tempo.

Os conceitos introduzidos pela SIMULA 67 serviram como base para o desenvolvimento de uma linguagem de programação voltada para tal estilo de desenvolvimento. Os conceitos alcançaram maturidade com a Smalltalk, que foi a primeira linguagem de programação realmente e totalmente OO. Mas, os programadores só se interessaram verdadeiramente por esse paradigma com o C++, devido a este ser muito parecido com o C e possuir compiladores bons e baratos e muitas vezes sem custos.

Baseados nesses conceitos, muitas outras linguagens surgiram, além de formas de modelagem de projetos, padrões etc. Mas, como nos dias de hoje escrever códigos em uma linguagem não orientada a objetos e não perder, pelo menos não completamente, o poder da OO?

Aqui são elucidados os principais passos para isso. Dessa forma programadores podem utilizar-se do projeto OO e implementá-lo em uma linguagem que não tem suporte a esse tipo de programação. Para isso será utilizado o C por possuir fraca verificação de tipos e por ser flexível o suficiente para proporcionar implementações dos conceitos abordados.

Transformação de classes em structs

Para começar vamos transformar classes em structs C. Todos os atributos de uma determinada classe deverão fazer parte dessas estruturas.

typedef struct projeto
{
int codigo;
}Projeto;

typedef struct criar
{
char* data[];

}Criar;

typedef struct desenho
{
int referencia;
char* nome[];
}Desenho;

typedef struct item_desenho
{
int codigo;
int quantidade;
}Item_desenho;

Passagem de argumentos para métodos (funções)

Em orientação objeto os métodos possuem no mínimo um argumento implícito (this, self etc). Nas linguagens não OO esse argumento deve ser explícito.

Quando o método faz alguma modificação no objeto, este deve ser passado como uma referência para aquele. Quando a modificação não for necessária a passagem pode ser por valor. Para que a programação fique mais uniforme, é melhor que todos os argumentos, pelo menos os objetos definidos pelo usuário, sejam passados por referência, até porque esta é menos custosa do que a outra.

Ex.:

Protótipos:

void set_projeto(Projeto* p)
void set_codigo_projeto(Projeto* p, int codigo)
int get_codigo_projeto(Projeto* p)

Chamadas:

Projeto* p

//a alocação será mostrada mais adiante

set_projeto(p);

Alocação de memória

Os objetos alocados dinamicamente são necessários quando sua quantidade não é conhecida em tempo de compilação. Assim acontece, por exemplo, com estruturas de dados como listas, árvores, grafos etc. A memória para eles deve ser solicitada explicitamente através de operadores especiais. Em C, isso acontece através das funções malloc e free, respectivamente.

Ex.:

Criação:

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

Remoção:

free(desenho);

    Próxima página

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

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

Ponteiros - Saindo de Pesadelos

A duplicação do buffer de saída na chamada de sistema fork() do Linux

Tutorial SFML

Projeto Icecream (parte 1)

  
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