PDA

Visualizza la versione completa : [C++] Classi template di strutture dinamiche lineari


dunix87
05-12-2007, 21:22
Salve, da qualche giorno sto sviluppando alcuni template sulle strutture dinamiche lineari come le code, le pile e le liste.

Nel corso dello sviluppo mi sono accorto di diversi problemi nella scrittura del codice. Più che altro di tipo teorico perchè credevo di aver fatto bene, ma poi dopo qualche suggerimento mi rendo conto che i miei sono errori di fondo.

Non posto l'intero codice della mia lista altrimenti sarebbe lungo, ma scrivero vari snippet per risolvere un problema alla volta.

La prima domanda che vi pongo è sull'uso degli iteratori, non c'è dubbio che siano di grande utilita, per quel che ho imparato so che è un puntatore per l'accesso agli elementi di un oggetto che contiene altri oggetti. Ora per sviluppare una lista ho implementato un iteratore molto semplice che però non riesco a compilare per via di un problema con la clausola friend.

Vi posto il codice dell'interfaccia:


template<class T>
class iterator
{
private:
nodo<T>* pos;//classe template nodo
public:
iterator();
iterator<T> &operator=(const iterator<T>&);
void operator++();
void operator--();
friend class list<T>;//Classe template lista
};

Quando provo a richiamare nel main un iterator<int> i; mi da un errore su friend class list<T> riportando 'list' is not a template...

Secondo voi cosa può essere? é inoltre la definizione di un iteratore in questo modo è corretta?

dunix87
06-12-2007, 13:54
Ho risolto da solo, la sintassi corretta per dichiarare la classe friend con la classe template, all'interno di una classe template era questa:

template <class> friend class Nome_classe_template;

A questo punto vi chiedo un ulteriore aiuto, più che altro dal punto di vista teorico.
Se io dichiaro una classe template, nel mio caso lo stack, nel seguente modo:

template<class T>
class stak{
...
private:
nodo<T> *testa;
public: void push(T const&);
...
};

template <class T>
void stack<T>::push(T const& dato){
nodo<T>* nuovo=new nodo<T>;
nodo->dato=dato;
nuovo->next=testa;
testa=nuovo;
};
//Nodo è una classe che ha T dato e nodo* next

Quando gli passo come T un tipo 'standard' tutto va bene, ma io vorrei capire meglio dal punto di vista teorico che succedde se gli passo un vettore, una stringa, una struttura o un oggetto cioè cosa ci sara in nodo->dato, un puntatore o l'intera oggetto/struttura...?

MacApp
06-12-2007, 14:02
l'intero oggetto/struttura (supponendo che nodo->dato sia di tipo T).
Osserva che naturalmente il compilatore non ti compila finché il tipo complesso T non ha tutti gli operatori che tu usi per nodo->dato.

dunix87
06-12-2007, 15:08
Osserva che naturalmente il compilatore non ti compila finché il tipo complesso T non ha tutti gli operatori che tu usi per nodo->dato.

Cioè, correggimi se ho capito male, devo ridefinire tutti gli operatori per l'oggetto T come quelli aritmetici, logici, d'incremento e condizionali?
Ma è comunque un lavoro assestante dalla mia classe nodo, giusto?

MacApp
06-12-2007, 15:24
Originariamente inviato da dunix87
Cioè, correggimi se ho capito male, devo ridefinire tutti gli operatori per l'oggetto T come quelli aritmetici, logici, d'incremento e condizionali?
Ma è comunque un lavoro assestante dalla mia classe nodo, giusto?
Solo gli operatori e metodi che utilizzi per il tuo modello nodo.

Ad esempio se nella tua classe modello effettui sqrt (nodo), allora devi definire la funzione sqrt che si prenda in argomento il tuo nodo di tipo tua classe, oppure un'operatore di casting dalla tua classe ad un tipo digeribile da sqrt. Altro esempio se nella tua classe modello, "nodo" non viene mai sommato ad un intero, allora non è necessario che la tua classe sia sommabile ad un intero. ecc..

Insomma se scrivi "nodo + 1" il compilatore deve sapere come farlo. E questo glielo puoi dire solo tu.
;-)

dunix87
06-12-2007, 15:37
Ah si ora ho capito...

Quindi se io uso la mia classe nodo all'interno sempre della stessa classe stack(esempio postato sopra), nella quale definisco un metodo di ricerca o di ordinamento(anche se non ha senso in una pila, ma mi serve solo da esmpio), devo ridefinire gli operatori di confrono <, >, == e !=, se passo un tipo oggetto allo stack, giusto?

Ma questa ridefinizione va fatta nella classe dell'oggetto che uso come tipo?
Non posso farla a priori nel mio template stack? e soprattutto se non li ridefinisco che succede potrebbe compilarlo ugualmente?

Grazie dei chiarimenti che mi stai fornendo

dunix87
07-12-2007, 16:46
Ho provato a ridefinire due operatori == e != per la classe che uso come tipo all'interno del mio stack per provare la funzione find. Ho provato a fare uno stack di stack.

Però il compilatore (dev c++) mi restituisce un errore di questo tipo:
no match for 'operator!=' in 'dato!=d'
candidates are 'bool stack<T>::operator==(stack<T>&)[with T=stack<int>]'

dato e d sono entrambi di tipo T (in questo caso sarebbero stack<int>).

Come posso risolvere questo errore, io proprio non capisco perchè non funzioni :confused:

MacApp
07-12-2007, 16:53
E' lo scotto da pagare nell'uso dei template: messaggi un po' forvianti negli errori di compilazione. Ma dopo un po' ci si abitua. Come li definisci gli operatori == e != ? Come vengono usati nella classe template?
insomma posta il codice.

dunix87
07-12-2007, 17:03
Infatti ho notato che si creano un po' di problemi.
Allora ti posto le definizioni degli operatori all'interno di stack:


template<typename T>
bool stack<T>::operator==(stack<T> &nuovo)
{return this == &nuovo;}

template<typename T>
bool stack<T>::operator!=(stack<T> &nuovo)
{return this != &nuovo;}

Mentre il codice del metodo find è il seguente:


template <class T>
iterator<T> stack<T>::find(T const &d){
iterator<T> iter;
iter.pos=this->top;
T dato=((iter.pos)->getData());//get data è un metodo che semplicemente ritorna T dat
while((dato!=d) && ((iter.pos)!=this->tail)) {
++iter;
dato=((iter.pos)->getData());//
}
if(dato==d) return iter;
else{
iter.pos=NULL;
return iter;
}
};

Spero di aver messo tutto

MacApp
07-12-2007, 18:27
Originariamente inviato da dunix87
Spero di aver messo tutto

Non basta: così si devono indovinare troppe cose. Posta qualcosa che secondo te dovrebbe essere compilabile, ma non lo è, e tutta la pappardella degli errori che ti genera.

intanto (se vuoi fare le cose fatte bene) metti a const gli argomenti ed i metodi che non ti servono non essere const:
ad esempio:



// MacApp: argomenti e metodi const
template<typename T>
bool stack<T>::operator==(const stack<T> &nuovo) const
{return this == &nuovo;}

template<typename T>
bool stack<T>::operator!=(const stack<T> &nuovo) const
{return this != &nuovo;}

Loading