Problema con le classi template

di il
10 risposte

Problema con le classi template

Buona sera, sto riscontrando dei problemi col seguente snippet di codice, relativo all'implementazione di una lista lineare generica con template:
#include <iostream>

using namespace std;

class Transazione
{
	public:
		Transazione(string f, string t, int q);
		
	private:
		string FROM;
		string TO;
		int QT;
};

Transazione::Transazione(string f, string t, int q)
{
	FROM=f;
	TO=t;
	QT=q;
}

template <class TIPO> class Nodo
{
	public:
		void set_next(Nodo <TIPO> *ptr);
		Nodo <TIPO> *get_next();
		void set_dati(TIPO data);
		TIPO get_dati();
	private:
		TIPO dati;
		Nodo *next;
};

template <class TIPO> void Nodo <TIPO>::set_next(Nodo <TIPO> *ptr)
{
	next=ptr;
}

template <class TIPO> Nodo <TIPO> *Nodo <TIPO> ::get_next()
{
	return next;
}

template <class TIPO> void Nodo <TIPO>::set_dati(TIPO data)
{
	dati=data;
}

template <class TIPO> TIPO Nodo <TIPO>::get_dati()
{
	return dati;
}

template <class TIPO> class Lista
{
	public:
		Lista();
		void aggiungi_in_coda(TIPO data);
		void stampa_lista();
		
	private:
		Nodo <TIPO> *head;
		Nodo <TIPO> *tail;
};

template <class TIPO> Lista <TIPO>::Lista()
{
	head=nullptr;
	tail=nullptr;
}

template <class TIPO> void Lista <TIPO>::aggiungi_in_coda(TIPO data)
{
	if(head==nullptr)
	{
		head=new Nodo <TIPO>;
		head->set_dati(data);
		head->set_next(nullptr);
		tail=head;
	}
	else
	{
		Nodo <TIPO> *punt=new Nodo <TIPO>;
		punt->set_dati(data);
		punt->set_next(nullptr);
		tail->set_next(punt);
		tail=punt;
	}
}

template <class TIPO> void Lista <TIPO>::stampa_lista()
{
	Nodo <TIPO> *ptr=head;
	
	while(ptr->get_next()!=nullptr)
	{
		cout<<ptr->get_dati()<<endl;
		ptr=(ptr->get_next());
	}
	cout<<ptr->get_dati()<<endl;
	ptr->set_next(ptr->get_next());
}

int main()
{
	Lista <Transazione> obj1;
	
	Transazione obj2("192.168.1.87", "192.168.1.17", 150);
	
	obj1.aggiungi_in_coda(obj2);
	
	obj1.stampa_lista();
	
	return 0;
}
Quando compilo il programma, mi dà una sfilza di errori, del tipo:
main.cpp:77:8: error: use of deleted function ‘Nodo<Transazione>::Nodo()’
   head=new Nodo <TIPO>;
   
main.cpp:84:21: error: use of deleted function ‘Nodo<Transazione>::Nodo()’
   Nodo <TIPO> *punt=new Nodo <TIPO>;
   
main.cpp:98:7: error: no match for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘Transazione’)
   cout<<ptr->get_dati()<<endl
   
/usr/include/c++/8/ostream:682:5: error: no type named ‘type’ in ‘struct std::enable_if<false, std::basic_ostream<char>&>’
Ho letto sul mio libro di C++ che quando il tipo generico di una classe templata (quello che qui ho chiamato TIPO) viene sostituito da un tipo non standard, ad esempio una classe definita dall'utente (come nel mio caso, la classe Transazione), il compilatore segnalerà un errore se non è stato ridefinito l'operatore utilizzato. Infatti se utilizzo la seguente dichiarazione:
Lista <int> obj1;
Passando pertanto valori interi alla funzione per aggiungere nodi alla lista, il programma funziona tranquillamente, anche per qualsiasi altro tipo di dato standard. Come posso risolvere questo problema, effettuando l'overload degli operatori che qui vengono utilizzati per inserire i nodi e stampare la lista? Ci sto perdendo un'intera giornata.

10 Risposte

  • Re: Problema con le classi template

    Per quanto riguarda il primo errore devi definire il costruttore di default per Transazione, per il secondo errore devi definire un overload dell'operatore << sempre per Transazione
  • Re: Problema con le classi template

    shodan ha scritto:


    Per quanto riguarda il primo errore devi definire il costruttore di default per Transazione, per il secondo errore devi definire un overload dell'operatore << sempre per Transazione
    Quindi gli attributi degli oggetti di classe Transazione non posso inizializzarli definendo un costruttore che lo faccia? Invece per quanto riguardo l'overload dell'operatore <<, è proprio questa la difficoltà che non riesco a superare... Ho provato ad implementare un tipo di overload, ma non funge. Potresti espormi un modo per poter risolvere questo problema?
  • Re: Problema con le classi template

    Si che puoi, ma il problema è che quando viene effettui un:
    
    head=new Nodo <TIPO>; // per esempio
    
    tu non passi nessun attributo, pertanto il compilatore si aspetta il costruttore di default.

    Per operator << metti così (poi vedi come completarlo)
    
    class Transazione
    {
    	public:
    		Transazione(string f, string t, int q);
                    ostream& operator<<(ostream& out, const Transazione& param);
    
  • Re: Problema con le classi template

    shodan ha scritto:


    Si che puoi, ma il problema è che quando viene effettui un:
    
    head=new Nodo <TIPO>; // per esempio
    
    tu non passi nessun attributo, pertanto il compilatore si aspetta il costruttore di default.

    Per operator << metti così (poi vedi come completarlo)
    
    class Transazione
    {
    	public:
    		Transazione(string f, string t, int q);
                    ostream& operator<<(ostream& out, const Transazione& param);
    
    Scusa la domanda forse banale e scontata, ma come posso implementare un overload dell'operatore << con il prototipo che mi hai suggerito tu? Perché ho capito che occorre un overload dell'operatore utilizzato, ma non mi è per niente chiaro come progettare concretamente la sua ridefinizione... Cioè come implementare praticamente l'overload.
  • Re: Problema con le classi template

    Scritto di fretta ho dimenticato il friend
    
    class Transazione
    {
    	public:
    		Transazione(string f, string t, int q);
                    friend ostream& operator<<(ostream& out, const Transazione& param);
                    
    ...
    
    
    ostream& operator << (ostream& out, const Transazione& param) {
    	out << param.FROM;
    	out << param.TO;
    	out << param.QT;
    	return out;
    }            
    
  • Re: Problema con le classi template

    shodan ha scritto:


    Scritto di fretta ho dimenticato il friend
    
    class Transazione
    {
    	public:
    		Transazione(string f, string t, int q);
                    friend ostream& operator<<(ostream& out, const Transazione& param);
                    
    ...
    
    
    ostream& operator << (ostream& out, const Transazione& param) {
    	out << param.FROM;
    	out << param.TO;
    	out << param.QT;
    	return out;
    }            
    
    OK, nel frattempo avevo tentato di implementare una soluzione del genere, ma la tua è migliore e più pulita; però con l'overload dell'operatore strutturato in questo modo, posso passare al << soltanto oggetti di classe Transazione, mentre io volevo realizzare una lista generica che potesse prendere in input qualsiasi oggetto di una qualsiasi classe, a prescindere dagli attributi che essa contiene, cioè realizzare un overload dell'operatore << in modo generico, tale da poter stampare qualsiasi tipo di attributo per una classe x. Detto in modo brutale, un overload che, per così dire, scorra tutti gli attributi dell'oggetto passato e li stampi nello standard output, senza definire gli attributi specifici da stampare, come proposto con la tua soluzione.

    È possibile realizzare una cosa del genere? Oppure la ridefinizione degli operatori utilizzati deve per forza essere strutturata su di una classe?
  • Re: Problema con le classi template

    [CODE] È possibile realizzare una cosa del genere? No. Ogni istanza di TIPO deve avere un proprio operator<<, pertanto se istanzi la lista con una fantomatica classe Pippo, Pippo dovrà avere un proprio operator << . Vige il principio che ogni classe è responsabile del proprio output.
  • Re: Problema con le classi template

    shodan ha scritto:


    [CODE] È possibile realizzare una cosa del genere? No. Ogni istanza di TIPO deve avere un proprio operator<<, pertanto se istanzi la lista con una fantomatica classe Pippo, Pippo dovrà avere un proprio operator << . Vige il principio che ogni classe è responsabile del proprio output.
    Perfetto, ora mi è molto più chiaro. Quindi Transazione dovrà avere il suo overload per l'operatore <<, Pippo un suo, Pluto un suo ancora, etc. Ultimissima domanda: per inizializzare gli attributi di Transazione col relativo costruttore, quali modifiche mi suggerisci di apportare al codice?
  • Re: Problema con le classi template

    Dipende dal compilatore.
    Se supporta questa sintassi:
    
    class Transazione
    {
    public:
    	constexpr Transazione() = default;
    	Transazione(string f, string t, int q);
    	friend ostream& operator << (ostream& out, const Transazione& param);
    
    private:
    	string FROM = "";
    	string TO = "";
    	int QT = 0;
    };
    
    allora è recente (almeno C++14).

    Altrimenti usi la sempre valida per tutti gli standard:
    
    class Transazione
    {
    public:
    	Transazione() : FROM(""), TO(""), QT(0) {}
    	Transazione(string f, string t, int q);
    	friend ostream& operator << (ostream& out, const Transazione& param);
    
    private:
    	string FROM;
    	string TO;
    	int QT;
    };
    
  • Re: Problema con le classi template

    shodan ha scritto:


    Dipende dal compilatore.
    Se supporta questa sintassi:
    
    class Transazione
    {
    public:
    	constexpr Transazione() = default;
    	Transazione(string f, string t, int q);
    	friend ostream& operator << (ostream& out, const Transazione& param);
    
    private:
    	string FROM = "";
    	string TO = "";
    	int QT = 0;
    };
    
    allora è recente (almeno C++14).

    Altrimenti usi la sempre valida per tutti gli standard:
    
    class Transazione
    {
    public:
    	Transazione() : FROM(""), TO(""), QT(0) {}
    	Transazione(string f, string t, int q);
    	friend ostream& operator << (ostream& out, const Transazione& param);
    
    private:
    	string FROM;
    	string TO;
    	int QT;
    };
    
    shodan, grazie mille per l'aiuto e per le delucidazioni! Ora il programma funziona correttamente e ho anche capito meglio i template e gli overload.

    Risolto!
Devi accedere o registrarti per scrivere nel forum
10 risposte