Vocês se lembram daqueles tópicos sobre ponteiros para funções? Eles me inspiraram a fazer um pequeno teste. Vocês já devem ter ouvido falar que a principal diferença entre structs e classes é que a primeira não pode ter funções dentro de si e que a segunda pode. Acabei de descobrir que é possível burlar essa limitação e com uma pequena gambiarra deixar o C uma linguagem mais voltada a objetos.
Se você ainda não leu os artigos sobre ponteiros para funções, dê uma lida pelo menos no primeiro, apenas para saber do que se trata. Depois de feita a leitura, vamos para um passo-a-passo do que foi feito. Primeiro, a definição de uma nova struct:
typedef struct {
void (*function)();
int i;
} class;
Você pode confirmar que estamos usando C e não C++, já que se fosse usado o segundo, ele daria um erro devido o mau uso da palavra class. O que foi feito aqui é bem simples: definimos uma estrutura com um ponteiro para uma função e um inteiro. Agora o segundo passo:
void fnc( class *this )
{
this->i++;
printf( "Function called %d time(s).\n", this->i );
}
Agora definimos a função que será usada pela estrutura a cima. Infelizmente, não temos um jeito de ter acesso ao this que teríamos no C++. Isso pode ser contornado colocando como argumento um ponteiro. Essa parte ainda será objeto de estudos.
A terceira parte é a criação de um constructor. Já que não estamos trabalhando de fato com uma classe, o ponteiro para a função começa vazio; temos então que ajustar tudo manualmente e para facilitar criamos uma função com esse propósito:
class Class()
{
class a;
a.i = 0;
a.function = &function;
printf( "Constructor called.\n" );
return a;
}
Agora quando estivermos dentro do main, criamos uma nova instância dessa estrutura/classe usando esse construtor. O único problema é a falta de um
this. Sem ele, não temos como acessar informações de dentro da struct sem passá
-la por referência, o que torna o esse método pouco prático. Talvez haja um jeito de
fazer o que eu quero usando macros.
O código todo:
#include <stdio.h>
typedef struct {
void (*function)();
int i;
} class;
void function( class *this )
{
this->i++;
printf( "Function called %d time(s).\n", this->i );
}
class Class()
{
class a;
a.i = 0;
a.function = &function;
printf( "Constructor called\n" );
return a;
}
int main( int argc, char* argv[] )
{
int count;
class test = Class();
for( count = 0; count < 10; count++ )
test.function( &test );
return 0;
}
Setembro 12, 2008 às 4:58 pm
Parabéns pelo post.
Muito útil.
Já vou aplicar isso ae.
Um abraço.
Novembro 1, 2009 às 6:55 am
Cara, gostei do seu blog. Você leva o raciocínio a fundo mesmo, a galera do C costuma falar muito e codar pouco. hehe
Sobre o C orientado eu também já me aventurei a brincar com os ponteiros de funções para simular uma pequena orientação. Só que o meu raciocínio tava bem diferente do seu, eu parti do pressuposto de que tudo era “tipo”, ao invés do conhecido tudo é “objeto”. Aí defini um tipo “Object”, um tipo “Class” e um tipo “method”. O problema é que uma biblioteca em C para tentar simular OO não poderia (eu acredito) dar a possibilidade de utilizar o paradigma da orientação mesmo, como Herança, Polimorfismo, encapsulamento, etc, porque isso seria implementado pelo usuário (o desenvolvedor) da biblioteca.
Por isso a necessidade de um outro compilador, como é no caso do C++. Na verdade, outra linguagem.
Voce já viu como é a Orientação à objetos em javascript?
function Person()
{
this.andar = function()
{
/** andando */
}
this.parar = function()
{
/** parar */
}
}
var aleteia = new Person();
aleteia.andar();
aleteia.parar();
Era dessa maneira que eu estava querendo fazer, passando o ponteiro das funções para as variaveis locais da classe (no caso a estrutura).
Olha esse link http://www.planetpdf.com/codecuts/pdfs/ooc.pdf
Aí o cara cria uma orientação completa em C ANSI, mas nada funcional ¬¬
falow.