Ir para conteúdo

Um exemplo polimórfico, em C


fredericopissarra

Posts Recomendados

A turma da OOP acredita que lidar com coisas como polimorfismo é impossível em linguagens "estruturadas". Eis um exemplo de como fazer uma lista de encadeamento simples, em C, com elementos de diversos "tipos"...

Considere a palavra-reservada struct: Ela existe para juntar vários tipos em um único container e de forma ordenada. Assim, se definirmos um nó genérico como:
 

typedef struct node_s {
  struct node_s *next;
} node_T; // _T porque _t não deve ser usado!

Podemos definir uma estrutura de controle para uma lista como:

// Usado para inicializar uma estrutura de lista vazia.
#define EMPTY_LIST { NULL, NULL }

typedef struct list_s {
  node_T *head, *tail;
} list_T;

Podemos agora usar a regra de que todo elemento que será colocado nessa lista deve definir, primeiro, um ponteiro do tipo node_T que aponte para o próximo item da lista... Por exemplo, suponha que eu queira criar uma lista de vetores 3D (x,y,z). Posso definir os elementos como:
 

struct vec3d_element_s {
  node_T *next;  // isso TEM que estar aqui!

  // nosso vetor:
  double x, y, z;
};

Eis uma rotina que adiciona elementos no início de uma lista:

// note que elemp é ponteiro para void, aceita qualquer ponteiro!
void addhead( list_T *lstp, void *elemp )
{
  node_T *p = elemp;

  p->next = lstp->head;
  lstp->head = p;  // o elemento é a nova 'cabeça' da lista.

  // Se a lista estiver previamente vazia, temos um novo 'rabo'.
  if ( ! lstp->tail )
    lstp->tail = p;
}

Note que, junto com a definição da estrutura de lista, defini um macro EMPTY_LIST. Isso permite o seguinte uso:

// define uma lista vazia.
list_T list = EMPTY_LIST;
struct vec3d_element_s *elemp; // ponteiro para nosso novo elemento.

elemp = malloc( sizeof *elemp ); // aloca elemento.
elemp->x = 0.0;    // inicializa dados do elemento.
elemp->y = 1.0;
elemp->z = sqrt(2.0);

// adiciona elemento na lista:
addhead( &list, elemp );

Note que nossa lista aceita QUALQUER estrutura que tenha, como seu primeiro membro, um ponteiro para node_T nomeado de next. Poderíamos fazer algo assim:

enum vec_type { V2D, V3D, V4D };

struct vec_element_s {
  node_T *next;
  enum vec_type vtype;

  double v[0]; // yep... tamanho 0!
};
...
list_T list = EMPTY_LIST;
...
// Aloca vetor 2D, inicializa-o e coloca na lista:
struct vec_element_s *v2d;
v2d = malloc( sizeof *v2d + 2*sizeof( double ) );
v2d->vtype = V2D;
v2d->v[0] = 1.0;
v2d->v[1] = 2.0;
addhead( &list, v2d );

// Aloca vetor 3D, inicializa-o e coloca na lista.
struct vec_element_s *v3d;
v3d = malloc( sizeof *v3d + 3*sizeof( double ) );
v3d->vtype = V3D;
v3d->v[0] = 1.0;
v3d->v[1] = 2.0;
v3d->v[1] = 3.0;
addhead( &list, v2d );

// percorre a lista e faz algo com os elementos:
node_T *p;

p = list.head;
while ( p )
{
  doSomething( p );
  p = p->next;
}

Na hora de percorrer a lista podemos usar o membro vtype para dedicir o tamanho do array v. Mas, note que a lista não se importa com o tipo do elemento, desde que ele tenha o ponteiro next como primeiro item.

Link para o comentário
Compartilhar em outros sites

PS; É claro... se quiser adicionar elementos no final da lista:
 

void addtail( list_T *lstp, void *elemp )
{
  node_T *p = elemp;
  
  // esse será o último elemento!
  p->next = NULL;

  if ( ! lstp->tail )  // lista vazia?
  {
    lstp->head = lstp->tail = p;
    return;
  }

  // ajusta o nó tail atual para o novo nó.
  lstp->tail->next = p;
  lstp->tail = p;
}

 

Link para o comentário
Compartilhar em outros sites

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...