PDA

Visualizza la versione completa : [C++]problema con template


Luc@s
29-03-2003, 20:09
Ho la seguente classe:


//////////////////////////////////////////////////////////////////////
// Vettore.h: interface for the Vettore class.
//
//////////////////////////////////////////////////////////////////////
#define DIM_STANDARD 10

template<class T>
class Vettore
{
public:
///////////////////////////////
// Costruttori/distruttori
///////////////////////////////
Vettore();
Vettore(int dim);
virtual ~Vettore();
///////////////////////////////
// Utilita di ricerca
///////////////////////////////
void Ordina();
int cerca(int size, T a[], T key);
///////////////////////////////
// Funzioni di interfaccia
///////////////////////////////
int getDimensione();
T getElemento(int pos);
///////////////////////////////
// Funzioni vettore
///////////////////////////////
void AggiungiElemento(T elemento, int pos);
void AggiungiElemento(T elemento);
void RimuoviElemento(int pos);

private:
T* elementi; // gli elementi
int dimensione; // la dimensione

};



Implementata cosi:

//////////////////////////////////////////////////////////////////////
// Vettore.cpp: implementation of the Vettore class.
//
//////////////////////////////////////////////////////////////////////
#include "Vettore.h"

//////////////////////////////////////////////////////////////////////
// Construttore a un argomento
//////////////////////////////////////////////////////////////////////
template<class T>
Vettore<T>::Vettore(int dim)
{
dimensione = (dim < 0) ? DIM_STANDARD : dim;
elementi[dim] = new T[dim];
for(int i=0;i<dimensione;i++)
{
dimensione[i] = NULL;
}

}

//////////////////////////////////////////////////////////////////////
// Construttore standard
//////////////////////////////////////////////////////////////////////
template<class T>
Vettore<T>::Vettore()
{
elementi[DIM_STANDARD] = new T[DIM_STANDARD];
dimenione = MAX;
for(int i=0;i<dimensione;i++)
{
dimensione[i] = NULL;
}
}

//////////////////////////////////////////////////////////////////////
// Distruttore standard
//////////////////////////////////////////////////////////////////////
template<class T>
Vettore<T>::~Vettore()
{
delete[] elementi;
}

//////////////////////////////////////////////////////////////////////
// Restituisce la dimensione
//////////////////////////////////////////////////////////////////////
template<class T>
int Vettore<T>::getDimensione()
{
return dimensione;
}
//////////////////////////////////////////////////////////////////////
// Ordina gli elementi
//////////////////////////////////////////////////////////////////////
template<class T>
void Vettore<T>::Ordina()
{
bool is_sorted=false;
int p=0,q=0;
T tmp;// la variabile temporanea di appoggio

while(!is_sorted){
is_sorted=true;
++p;// p viene avanzato e poi visualizzato
for(q=0;q<size-p;++q){
if(elementi[q]>a[q+1]){
tmp=elementi[q];
elementi[q]=elementi[q+1];
elementi[q+1]=tmp;
is_sorted=false;// esce dal for
}
}
}
}
//////////////////////////////////////////////////////////////////////
// Reicerca elementi
//////////////////////////////////////////////////////////////////////
template<class T>
int Vettore<T>::cerca(int size, T a[], T key)
{
for(int i=0;i<size;i++)
{
if(a[i] == key)
return i;
}

return -1;
}
//////////////////////////////////////////////////////////////////////
// Aggiunge un elemento (con posizione specificata)
//////////////////////////////////////////////////////////////////////
template<class T>
void Vettore<T>::AggiungiElemento(T elemento, int pos)
{
if( (pos <= dimensione) && (pos > 0) )
elementi[pos] = elemento;
}

//////////////////////////////////////////////////////////////////////
// Aggiunge un elemento (senza posizione specificata)
//////////////////////////////////////////////////////////////////////
template<class T>
void Vettore<T>::AggiungiElemento(T elemento)
{
for(int pass=0;pass<dimensione;pass++)
{
if(elementi[pass] == NULL)
elementi[pass] = elemento
break; // esce dal for
}
}
//////////////////////////////////////////////////////////////////////
// Restituisce un elemento (posizione specificata)
//////////////////////////////////////////////////////////////////////
template<class T>
T Vettore<T>::getElemento(int pos)
{
return elementi[pos];
}
//////////////////////////////////////////////////////////////////////
// Rimuove un elemento (con posizione specificata)
//////////////////////////////////////////////////////////////////////
template<class T>
void Vettore<T>::RimuoviElemento(int pos)
{
if( (pos <= dimensione) && (pos > 0) )
elementi[pos] = NULL;
}


E ho questo test:

// test.cpp
#include <iostream>
#include "Vettore.h"

using namespace std;

int main()
{
Vettore<int> vet(5);
vet.AggiungiElemento(3, 1);
vet.AggiungiElemento(5);
vet.Ordina();
for(int i;i<vet.getDimensione();i++)
{
cout << "Vettore " << i << ": " << vet.getElemento(i)<<endl;
}
return 0;
}

Ma mi da:


Test.obj : error LNK2001: unresolved external symbol "public: virtual __thiscall Vettore<int>::~Vettore<int>(void)" (??1?$Vettore@H@@UAE@XZ)
Test.obj : error LNK2001: unresolved external symbol "public: int __thiscall Vettore<int>::getElemento(int)" (?getElemento@?$Vettore@H@@QAEHH@Z)
Test.obj : error LNK2001: unresolved external symbol "public: int __thiscall Vettore<int>::getDimensione(void)" (?getDimensione@?$Vettore@H@@QAEHXZ)
Test.obj : error LNK2001: unresolved external symbol "public: void __thiscall Vettore<int>::Ordina(void)" (?Ordina@?$Vettore@H@@QAEXXZ)
Test.obj : error LNK2001: unresolved external symbol "public: void __thiscall Vettore<int>::AggiungiElemento(int)" (?AggiungiElemento@?$Vettore@H@@QAEXH@Z)
Test.obj : error LNK2001: unresolved external symbol "public: void __thiscall Vettore<int>::AggiungiElemento(int,int)" (?AggiungiElemento@?$Vettore@H@@QAEXHH@Z)
Test.obj : error LNK2001: unresolved external symbol "public: __thiscall Vettore<int>::Vettore<int>(int)" (??0?$Vettore@H@@QAE@H@Z)
Debug/Vettore.exe : fatal error LNK1120: 7 unresolved externals
Error executing link.exe.

r0x
30-03-2003, 15:23
Di classi e funzioni template devi scrivere tutto il codice dentro l`header, sia dichiarazioni che definizioni. Per il resto ci sono svariati errori:

1)



elementi[dim] = new T[dim];
for(int i=0;i<dimensione;i++)
{
dimensione[i] = NULL;
}


Diventa:



elementi = new T[ dim ];

// e nient`altro, tanto si affida al costruttore di default


Stesso discorso per Vettore().

2) Posto cosi`, cerca() andrebbe reso static perche` non si fa minimo cenno all`oggetto chiamante, e forse non e` quello che intendevi fare. Quindi:



int Vettore<T>::cerca(int size, T a[], T key)
{
for(int i=0;i<size;i++)
{
if(a[i] == key)
return i;
}

return -1;
}


Diventa:



int Vettore< T >::cerca( T key )
{
for( int i = 0; i < dimensione; ++i )
{
if( elementi[ i ] == key )
return i;
}

return -1;
}


3) I metodi AggiungiElemento()/RimuoviElemento() li vedo un po` "bizzarri".. :eek: Inoltre questa condizione e` errata:



(pos <= dimensione) && (pos > 0)


Piuttosto:



(pos < dimensione) && (pos >= 0)


Per l`accesso agli elementi usa il piu` intuitivo operator[].

l-value:



template< class T >
T& Vettore< T >::operator[]( size_t pos )
{
return elementi[ pos ];
}


r-value:



template< class T >
const T& Vettore< T >::operator[]( size_t pos ) const
{
return elementi[ pos ];
}


Ciao.

Zalex
30-03-2003, 17:09
Originariamente inviato da r0x
Di classi e funzioni template devi scrivere tutto il codice dentro l`header, sia dichiarazioni che definizioni.

Questo non e' sempre vero!dipende dal compilatore........cmq e' sempre meglio mettere tutto nell'header!


per quando riguarda il codice di luc@s, contiene un po' di errori......
a parte un punto e virgola mancante
..........
if(elementi[pass] == NULL)
elementi[pass] = elemento;
break; // esce dal for
...........
e una inizializzazione credo dimenticata(nel main)
for(int i=0;i<vet.getDimensione();i++)
{
cout << "Vettore " << i << ": " << vet.getElemento(i)<<endl;
}
che puo capitare :D ,
te ne elenco alcuni:
Nel costruttore a un argomento
-elementi[dim] = new T[dim]; la new ritorna un puntatore,in questo caso un int * che non puoi assegnare a un int

-for(int i=0;i<dimensione;i++)
{
dimensione[i] = NULL;
}
dimensione ha tipo int!come fai a usare il subscripting??non e' un array!

-nel metodo Ordina(): 'size' da dove salta fuori?e la 'a'?

-nel metodo AggiungiElemento c'e' un controllo un po strano...(secondo me):master:
if(elementi[pass] == NULL)non e' un confronto tra puntatori!e NULL lo vedrei piu in un confronto tra puntatori

per quanto riguarda il metodo cerca,ritengo che non abbia senso l'implementazione da te fornita per un semplice motivo : perche' passare per valore l'array in cui cercare?allora a cosa serve la classe,l'oggetto di invocazione,ecc?non avrebbe nemmeno senso falo static perche' non e' un metodo inerente alla classe!cioe' ci potrebbero essere contemporaneamente piu' istanze della stessa classe e una ricerca statica dove cerca?la nuova implementazione di r0x mi sembra piu sensata.

bhe credo che correggendo questi (piccoli?) errori e rivedendo meglio il metodo Ordina possa funzionare abbastanza bene.....anche se in questi casi preferisco usare le liste,ma questo e' solo un punto di vista:D
ciao

r0x
30-03-2003, 17:49
Questo non e' sempre vero!dipende dal compilatore........cmq e' sempre meglio mettere tutto nell'header!


In un modo o nell`altro, l`importante e` che il corpo della classe/funzione template che si intende utilizzare in un sorgente sia visibile. Poi certo la procedura e` specifica del compilatore. Cmq se metti la definizione nell`header vai tranquillo e ti eviti noie non indifferenti.

Per lo static: sintatticamente altroche` se ha senso, effettua la ricerca nell`array passato come parametro. E` naturalmente _ovvio_ che un metodo del genere non serve a un ca**o. :p

Luc@s
30-03-2003, 18:59
risolto!

TheGreatWorld
30-03-2003, 20:39
Per Zalex: certo che e' sempre vero, ovvero secondo quello che dice l'ISO C++. Se vuoi dividere la definizione dalla dichiarazione devi usare la parola chiave export da applicare alla dichiarazione.

Bye

Loading