Newsgroup: it.comp.lang.c++
Titolo: Cosa ne dite??

Ciao,
premeto che il C++ mi è ancora un bel po' oscuro comunque ho scritto questo
piccolissimo programma che implementa una "lista".
Funziona ma ho paura che sia un po' una schifezza, cosa ne dite?
vi sarei molto grato se potreste darmi qualche consiglio, sia su come
migliorare questo codice sia su quali altre operazioni inserire nelle
gestione della lista.
#include <conio.h>
#include <iostream.h>
class ListElement;
typedef ListElement* elemento;
class ListElement {
private:
   int value;
    elemento next;
public:
ListElement();
void PushE(int newe);
    void PushL(elemento newl);
    int PopE();
    elemento PopL();
};
ListElement :: ListElement() : next(NULL) {
}
int ListElement :: PopE() {
    return value;
}
elemento ListElement :: PopL() {
    return next;
}
void ListElement :: PushE(int newe) {
    value = newe;
}
void ListElement :: PushL(elemento newl) {
    next = newl;
}
elemento insert(int e, elemento l) {
elemento t;
   t = new ListElement;
   t->PushE(e);
   t->PushL(l);
   return t;
}
void main(void) {
elemento root = NULL;
    elemento l;
   int i;
   do {
    cout << "Introduzione valore: ";
    cin >> i;
    root = insert(i, root);
   }while(i != 0);
   // stampa
   l = root;
   while(l != NULL) {
    cout << "Valore estratto:" << l->PopE() << endl;
      l = l->PopL();
   }
   getch();
}
Ringrazio e saluto tutti.
                                                Pevar...



gestione della lista.
Un commento sulla realizzazione attuale:
Hai utilizzato benissimo i concetti di information hiding,
dato che hai costruito 4 funzioni membro pubbliche
per fare operazioni di get/set sui membri int e elemento.
[funzioni di accesso alle veriabili membro, in gergo]
Pero' la logica piu' importante della lista non e' stata
"incapsulata" abbastanza.
Sostanzialmente hai definito il concetto di elemento, ma non quello
di lista, dato che l'operazione forse piu' importante (l'inserzione
per il momento, visto che la cancellazione manca) l'hai implmentata
con una funzione "totalmente esterna" alla lista stessa.
A mio personale modo di vedere sarebbe piu' utile avere una
classe lista che "contiene" uno (o piu' elementi).
Qualcosa del genere:
class Node {
public:
    int value;
    Node *pNext;
}
class Lista {
private:
    Node * m_pNode;
public:
    Lista();
    Lista(int value);
    Insert(int position);
    Delete(int value);
    ~Lista();
friend
    ostream & operator<<(ostream &os,Lista & MyList);
}
Magari potresti raffinare la visibilita' dei membri,
ed implemntare un distruttore che liberi la memoria
allocata con "new Node".
Aspetta comunque la risposta di Alex Martelli, che sembra
sempre avere delle idee molto chiare rigurado alla
progettazione C++. Forse ti potrebbe suggerire di dare una
occhiatina alla SC++L, o di usare i template ...

gestione della lista.
I nomi dei metodi 'push' e 'pop' sono piuttosto ingannevoli: essi
suggeriscono un comportamento tipo 'stack', che in realta` non
e` connaturato alla tua struttura dati e in effetti non e` da essi
implementato (le 'pop' non modificano la lista, ad esempio).  Nomi
a parte, le 'pop' dovrebbero essere const appunto perche` non
modificano nulla quindi dovrebbe essere lecito chiamarle su di
un oggetto non modificabile.
Non c'e` molto altro che avrebbe senso mettere in una struttura
dati di lista non-invasiva semplicemente linkata; i due mutatori
e i due accessori che fornisci espongono "tutto", quindi altre
funzioni e` meglio implementarle esternamente (come hai fatto
per la insert).  Potrebbe essere un po' piu` efficiente avere le
funzioni inline, ma non ha una grande importanza.
Sarebbe meglio che il costruttore accettasse il valore iniziale
del dato (con default a 0) e lo applicasse, per non rischiare di
avere mai un nodo con un dato non inizializzato.
Alex

occhiatina alla SC++L, o di usare i template ...
La generalizzazione ottenuta usando i template avrebbe
sicuramente i suoi vantaggi, ma non mi era venuto in
mente di farlo notare in questo caso, quindi grazie di
avermelo ricordato:-).
La libreria Standard C++ non prevede purtroppo un
contenitore "lista semplice" (la std::list e` doppiamente
linkata, con un overhead quindi di DUE puntatori per
nodo: nel 99% dei casi andra` benissimo, ma c'e`
sempre quell'1% in cui i 4 byte in piu` per nodo vanno
ottimizzati via anche a prezzo di tante funzionalita`).
La std::slist<> e` una estensione SGI, non presente
nello Standard vero e proprio (scelta discutibile ma
difendibile quella del comitato di standardizzazione,
visto che si tratta appunto di una struttura dati di uso
raro e specialistico).
Alex

Grazie per le risposte e per l'incoraggiamento che esse mi danno.
vorrei comunque farvi una domanda.
A quanto pare la lista che ho implementato è una lista non invasiva
semplicemente linkata .
Ma cosa vuol dire?
Quali altri tipi di liste esistono e a cosa servono?
Ciao e grazie.
                            Pevar...

Quali altri tipi di liste esistono e a cosa servono?
Lista invasiva (piu` efficiente, ma si applica solo a lista
di classi appositamente progettate per stare in lista!):
    class Impiegato {
        Impiegato* next;
    public:
        // eccetera
    };
lista non-invasiva:
    class NodoImpiegato {
        Impiegato* questo;
        NodoImpiegato* next;
    public:
        // eccetera
    };
La lista non-invasiva ti costa un puntatore in piu`
per nodo (e l'accesso e` indiretto, quindi piu`
lento; inoltre, dato solo un impiegato, non puoi
agevolmente determinare in quali 0 o piu` liste
esso si trovi; ecc); e` piu` flessibile (puoi appunto
avere un impiegato su 0 o piu` liste, invece che
su esattamente 1).  Non sono due usi mutualmente
esclusivi, puoi avere una lista invasiva per il
"contenitore primario" e 0+ liste non invasive
degli stessi tipi per vari usi ausiliari.
Lista doppiamente linkata: ogni nodo punta anche
al precedente oltre che al successivo, quindi
muoversi sulla lista, bidirezionalmente, diventa
MOLTO agevole.
Con una lista semplicemente linkata, tante operazioni
"ovvie" sono disastrose come complicazioni e
prestazioni: ad esempio, dato un puntatore a un
nodo della lista, come fai a togliere quel nodo dalla
lista?  Risposta: devi partire dall'inizio della lista
e trovare il PREDECESSORE di quel nodo, perche`
la "rimozione dalla lista" consiste nel settare il
Next del _predecessore_ (a quello che ora era il
Next del nodo che stiamo eliminando).  Giusto per
fare un esempio...!
Con una lista doppiamente linkata, togliere un nodo
da una lista diventa banalmente facile:
    if(Next) Next->Previous = Previous;
    if(Previous) Previous->Next = Next;
fatto!  Le operazioni che sono diabolicamente
difficili e mal-prestanti su una lista semplicemente
linkata, e banali e velocissime su di una doppiamente
linkata, sono TANTE, ma TANTE.  Per questo, la
lista semplicemente linkata va considerata un "caso
particolare", da usare solo a fronte di specifiche e
particolari esigenze di uso in condizioni di memoria
molto scarsa e preziosa, e cose del genere.
Il C++ Standard ti fornisce una eccellente
implementazione delle liste doppiamente linkate:
    #include <list>
    using std::list;
adesso, per usare una lista di interi, basta che
tu usi list<int>, una lista di oggetti di class Pippo
list<Pippo>, una lista di puntatori a tali oggetti
list<Pippo*>, e cosi` via, senza limiti.
Si tratta di liste non-invasive (se non non potresti
mai avere una list<int>, ad esempio...!-).  Lo
Standard fornisce anche gran copia di algoritmi
per operare comodamente con queste (e tante
altre) strutture dati.
Alex

Grazie per l'aiuto.
        Pevar...