Newsgroup: it.comp.lang.c
Titolo: Implementazione ADT

Salve a tutti ragazzi. Iniziamo con una spiegazione del perchè sono
arrivato ad aprire questa discussione.
Devo sviluppare un progetto, e ho bisogno di implementare delle code,
oltretutto devo poter cambiare due tipi di implementazione senza
modificare il programma principale. Questo non è un problema, il
problema è come mi è stato chiesto di fare.
Ho il programma principale che avrà:
#include "coda.h"
#include "coda.c"
dove in "coda.h" ci sono le dichiarazioni di tipo e i prototipi, in
"coda.c" l'implimentazione. A questo punto mi si chiede di cambiare
solo "coda.c", facendo in modo che il programma principale diventi:
#include "coda.h"
#include "coda2.c"
A questo punto, le due implementazioni sono con array e liste legate.
Quindi le definizioni di tipo cambiano, perchè nella prima
implementazione il tipo Coda è definito:
typedef int *Coda;
nella seconda è definito:
typedef struct nodo {
  int info;
  struct nodo *next;
} Coda;
Il mio dilemmma è come fare a cambiare il .c senza cambiare il .h?
Mi è stato suggerito di sfruttare un ulteriore livello di indirezione,
ma non capito in che modo. E la mia domanda è un pò più generale,
perchè sto cercando di capire un pò più il discorso degli ADT in
generale, che questo particolare problema. Grazie in anticipo a tutti.

 Mi è stato suggerito di sfruttare un ulteriore livello di indirezione,
Puoi fare cosi', nel coda.h:
typedef int ELEMENTO;
typedef void * CODA;
e poi hai i prototipi dei tuoi metodi:
CODA Coda_Crea(void);
void Coda_Distruggi(CODA c);
void Coda_Aggiungi(CODA c, ELEMENTO e);
ELEMENTO Coda_Estrai(CODA c);
ed eventuali altri.
Nel file di implementazione (quello nascosto), avrai:
----------------------------------------------------
/*
  * coda1.c -- Implementazione ad array
  */
#include "coda.h" /* interfaccia comune */
typedef struct _CodaArray {
    ELEMENTO * info; /* array con i dati */
} CODA_ARRAY;
/* Crea una coda, usando array */
CODA Coda_Crea(void)
{
   CODA_ARRAY * c;
   c = malloc(sizeof(CODA_ARRAY));
   if (c == NULL)
     return NULL;
   c->info = NULL; /* per ora e' vuota */
   return (CODA)c;
}
...e cosi' via per gli altri metodi
----------------------------------------------------
Nel caso di code con liste:
----------------------------------------------------
/*
  * coda2.c -- Implementazione con liste
  */
#include "coda.h"
typedef struct _Nodo {
    ELEMENTO info;
    struct _Nodo *next;
} NODO;
/* Crea coda usando liste */
CODA Coda_Crea(void)
{
   NODO * nodo;
   nodo = malloc(sizeof(NODO));
   if (nodo == NULL)
     return NULL;
   nodo->info = 0;
   nodo->next = NULL;
   return (CODA)nodo;
}
----------------------------------------------------
Puo' darsi via sia qualche errore di sintassi (non ho compilato), ma il 
concetto dovrebbe essere chiaro.
...altrimenti studia meglio il C (ripeto, c'e' gia' un errore riguardo 
l'#include "coda.c" !!!).

Grazie mille per il tuo aiuto. Per quanto riguarda l'inclusione del .c
lo so che non si include. Infatti non capisco perché mi è stato
chiesto di fare in questo modo, quando i prog li faccio a modo mio
includo solo il .h. Grazie mille per l'aiuto, sei stato molto utile.

Ti ringrazio mille per l'aiuto che mi hai dato, sono riuscito ad
ottenere alla fine il risultato cercato. Ho solo un piccolo problemino.
Ho bisogno di implementare una funzione stampa_coda che mi stampa tutti
gli elementi della coda. Per implementarla ho fatto uso di una funzione
stampa_elemento, in modo che stampa_coda rimane la stessa se dovesse
cambiare il tipo degli elementi della coda e si deve modificare solo
questa stampa_elemento. A questo punto, volevo inserire stampa_elemento
nel .h, in modo da poterla modificare quando si modifica il tipo e in
modo da tenerla comune in entrambe le implementazioni.
Però linkando il .c (non l'ho incluso, almeno per il momento), mi dà
un errore di compilazione dicendo che c'è una definizione multipla di
questa procedura, io il .h l'ho anche racchiuso tra le istruzione
#ifndef
#define
#endif
ma il problema sussiste. E penso sia perchè il .h è incluso sia nel
prog principale che nell'implementazione della libreria, come si fa?
Grazie anticipatamente.

 questa procedura, 
Il linker ha ragione :)
Non puoi definire piu' di una volta una stessa funzione, ecco perche' le 
funzioni non si *definiscono* nei .h (si *dichiarano* nei .h).
dichiarare = dare il prototipo
definire = prototipo + corpo della funzione
dichiarazione --> quante volte vuoi
definizione --> una sola volta
Se proprio vuoi usare quell'approccio, potresti pensare alle macro del 
preprocessore, cioe', nel .h, fai:
#define STAMPA_ELEMENTO(x) .....
...pero' le macro sono una cosa delicata, devi stare attento, 
soprattutto se non sei esperto.
Oppure puoi provare con "inline" (ma non so se e' entrato nello standard 
C ANSI, ad es. il Microsoft Visual C++ lo supporta anche quando compili 
sorgenti C, non C++).
Le definizioni di funzioni inline le puoi inserire nei .h.
Ciao