PDA

View Full Version : [c++]template di classe


crystal86
21-03-2008, 16:56
Buonasera. Ho un piccolo problema da esporre. Ho questa classe:

#ifndef ATTRIBUTOVALORE_H
#define ATTRIBUTOVALORE_H
#include "string.h"

using namespace std;

template <class T>
class AttributoValore{

public:
AttributoValore(T,string);
~AttributoValore();
bool setAttribute(string Attribute);
bool setValue(T Value);
T getValue();
string getAttribute();
private:
T value;
string attribute;
};

#endif

e poi ho definito quest'altra classe:

#ifndef FATTO_H
#define FATTO_H
#include <list>
#include <string>
#include "attributovalore.h"

using namespace std;


class Fatto {

public:
Fatto(AttributoValore AV);
~Fatto();
bool setFactName(string name);
bool addAttVal(AttributoValore AV);
private:
string Name;
list<AttributoValore> Attributi;
};

#endif
in fase di compilazione mi da errore precisamente quando vado a definire variabili di tipo "AttributoValore". Mi da errori del tipo manca la virgola o la parentesi. Credo il problema sia dovuto al fatto che ho usato i template di classe. Qualcuno sa illuminarmi? grazie in anticipo:help:

fek
21-03-2008, 17:09
Quando usi la classe parametrica devi indicare al compilatore che tipo vuoi:

AttributoValore<int>
AttributoValore<char>
AttributoValore<MyClass>

In questo modo il compilatore e' in grado di generare una classe completa usando rispettivamente int, char o MyClass al posto di T.
Inoltre devi dichiarare tutti i metodi della classe template inline nel .hpp di modo che il compilatore li abbia disponibili al momento dell'instanziazione del template.

Ti stai andando a cacciare in un grosso guaio con i template, occhio.

crystal86
21-03-2008, 17:22
quindi devo per forza già dire adesso quale sarà il tipo T, e non c'è un modo per dirlo successivamente?

comunque adesso ho modificato la classe cosi

#ifndef FATTO_H
#define FATTO_H
#include <list>
#include <string>
#include "attributovalore.h"

using namespace std;

typedef AttributoValore <int> AttributoV;

class Fatto {

public:
Fatto(AttributoV AV);
~Fatto();
bool setFactName(string name);
bool addAttVal(AttributoV AV);
private:
string Name;
list<AttributoV> Attributi;
};

#endif

e mi da ancora errore precisamente:

C:\Documents and Settings\Teddy\Documenti\Università\ICSE\Interprete\fatto.o(.text$_ZSt8_DestroyI15AttributoValoreIiEEvPT_[void std::_Destroy<AttributoValore<int> >(AttributoValore<int>*)]+0xd) In function `ZNSt10_List_baseI15AttributoValoreIiESaIS1_EE11_M_get_nodeEv':

[Linker error] undefined reference to`AttributoValore<int>::~AttributoValore()'



ho controllato il codice ma non mi pare ci siano errori di sintassi. Idee in merito? grazie per le risposte

fek
21-03-2008, 17:31
quindi devo per forza già dire adesso quale sarà il tipo T, e non c'è un modo per dirlo successivamente?

La classe template e' proprio il modo di implementare un comportamento per il quale il tipo esatto non e' ancora conosciuto, e verra' indicato dopo. Quando usi la classe template devi indicare il tipo, altrimenti il compilatore non sa che quale codice generare perche' non gli dici che cosa e' T.


[Linker error]

Devi implementare i metodi della classe template, se non li scrivi il compilatore come fa a sapere che cosa fa ogni metodo?

Esempio:



class MyFirstTemplate<typename T>
{
MyFirstTemplate()
{
// initialise class here
}

T Get(T& x) const
{
return x;
}
};


void main()
{
MyFirstTemplate<int> object_of_int; // instatiate MyFirstTemplate<int> here (well, a bit above)

assert(5 == object_of_int.Get(5)); // works!?
}

crystal86
21-03-2008, 17:39
Ho capito la questione dei template.

Per quanto riguarda il codice avevo già implementato i metodi:

della prima classe

#include <iostream>
#include "attributovalore.h"
#include "string.h"

using namespace std;

template <class T>
AttributoValore<T>::AttributoValore(T valore, string attributo)

{

value=valore;
attribute=attributo;

}

template <class T>
AttributoValore<T>::~AttributoValore(){

cout<<"Coppia attributo-valore eliminata\n";
}

template <class T>
bool AttributoValore<T>::setAttribute(string Attribute)

{
attribute=Attribute;
if (attribute=="")

return false;

else
return true;
}

template <class T>
bool AttributoValore<T>::setValue(T Value)

{
value=Value;
if (value=="")

return false;

else
return true;
}


e della seconda classe

#include "fatto.h"
#include <string>
#include <list>
#include <iostream>
#include "attributovalore.h"

using namespace std;

Fatto::Fatto(AttributoV AV){

Attributi.push_front(AV);

}

Fatto::~Fatto(){

cout<<"Fatto eliminato\n";

}

bool Fatto::addAttVal(AttributoV AV)
{

Attributi.push_front(AV);
if(Attributi.empty())
return true;
else
return false;
}

bool Fatto::setFactName(string name)
{
Name=name;
if(Name=="")
return false;
else
return true;
}

il problema persiste. Ho provato a utilizzare la classe AttributoValore in un altro progetto e in fase di compilazione non mi da errori. Presumo quindi che il problema sia nella classe Fatto.

fek
21-03-2008, 17:41
il problema persiste. Ho provato a utilizzare la classe AttributoValore in un altro progetto e in fase di compilazione non mi da errori. Presumo quindi che il problema sia nella classe Fatto.

No, il problema e' che devi implementare i metodi inline come ho fatto io nel mio esempio. Il compilatore deve avere l'intera definizione della classe e dei suoi metodi in ogni unita' di traslazione che istanzia un template. Tante parole difficili per dire: definisci i metodi della classe template inline nel file .h, includilo dove usi la classe template, e funzionera' tutto.

crystal86
21-03-2008, 18:00
No, il problema e' che devi implementare i metodi inline come ho fatto io nel mio esempio. Il compilatore deve avere l'intera definizione della classe e dei suoi metodi in ogni unita' di traslazione che istanzia un template. Tante parole difficili per dire: definisci i metodi della classe template inline nel file .h, includilo dove usi la classe template, e funzionera' tutto.

grazie mille ho risolto come hai detto tu. Senti ma il fatto che non posso separare l'implementazione dei metodi dalla definizione della classe è dovuto all'uso dei template?

cionci
22-03-2008, 00:22
Sì...questo perché le classi relative ai vari tipi di dati vengono generate in fase di compilazione.

fek
22-03-2008, 11:21
grazie mille ho risolto come hai detto tu. Senti ma il fatto che non posso separare l'implementazione dei metodi dalla definizione della classe è dovuto all'uso dei template?

Si', come ha detto cionci il codice che deriva da una classe template e' generato a tempo di compilazione.
Il processo si chiama istanziazione di un template: ogni volta che indichi esplicitamente i tipi associati ad una classe template, il compilatore crea letteralmente il codice di una nuova classe in quel punto (un po' prima in realta') e relativi metodi, sostituendo letteralmente ai tipi parametrici i tipi reali che hai indicato. Per fare questo ha bisogno di tutte le informazioni della classe template, quindi di tutte le dichiarazioni e tutti i metodi implementati.