Foros del Web » Programación para mayores de 30 ;) » C/C++ »

Una Lista Enlazada con Plantillas en C++(duda)

Estas en el tema de Una Lista Enlazada con Plantillas en C++(duda) en el foro de C/C++ en Foros del Web. Hola a todos! Tengo una duda acerca de las templates en C++. Despues de leer varios tutoriales, por fin pude crear por mi cuenta una ...
  #1 (permalink)  
Antiguo 29/12/2010, 04:33
 
Fecha de Ingreso: diciembre-2010
Mensajes: 4
Antigüedad: 13 años, 4 meses
Puntos: 0
De acuerdo Una Lista Enlazada con Plantillas en C++(duda)

Hola a todos!

Tengo una duda acerca de las templates en C++.
Despues de leer varios tutoriales, por fin pude crear por mi cuenta una Lista Simplemente Enlazada utilizando plantillas y dos clases(Nodo y Lista).

Mi pregunta es:
¿Por que cuando tengo todo mi código junto en un solo archivo, cuando compilo y corro mi programa funciona perfecto, pero cuando separo el codigo en archivos de cabecera(.h y .cpp) mas el main.cpp mi compilador(g++) al momento del enlazado me tira varios errores?

Mi codigo TODO JUNTO el que si funciona es:
Código:
#include <iostream>
using namespace std;

template <class Q>
class Nodo{
	private:
		Q *MiDato;
		Nodo<Q> *next;
	public:
		Nodo(Q nuevo){
			next = NULL;
			MiDato = new Q;
			*MiDato = nuevo;
		}
		Nodo(void): MiDato(NULL), next(NULL) {}
		~Nodo(void){
			delete MiDato;
			next = NULL;
		}
		void set_data(Q nuevo){
			MiDato = new Q;
			*MiDato = nuevo;
		}
		void set_next(Nodo<Q> *s) { next = s; }
		const Q get_data(void) const { return *MiDato; }
		Nodo<Q> *get_next(void) { return next; }
		void ShowAll(void) const{
			Nodo<Q> *aux = next;

			cout << *MiDato << endl;
			while(aux){
				cout << aux->get_data() << endl;
				aux = aux->get_next();
			}
		}
};

template <class Q>
class Lista{
	private:
		Nodo<Q> *inicio;
		Nodo<Q> *final;
		int tam;
	public:
		Lista(void): inicio(NULL), final(NULL), tam(0) {}
		~Lista(void){
			Nodo<Q> *aux = inicio;

			if(!empty()){
				while(inicio){
					inicio = inicio->get_next();
					delete aux;
					aux = inicio;
				}
			}
			final = NULL;
			tam = 0;
		}
		void add(Q nuevo){
			Nodo<Q> *aux = new Nodo<Q>(nuevo);
			if(empty()){
				inicio = aux;
			}else{
				final->set_next(aux);
			}
			final = aux;
			tam++;
		}
		int get_tam(void) const { return tam; }
		bool empty(void) const{
			return (inicio == NULL);
		}
		void Mostrar(void) const { inicio->ShowAll(); }
};

int main(void){
	Lista<int> Buena;
	Lista<char> Mala;

	for(int i = 10; i < 21; i++){
		Buena.add(i);
	}
	Mala.add('M');
	Mala.add('A');
	Mala.add('L');
	Mala.add('A');

	cout << "Buena mide: " << Buena.get_tam() << endl;
	Buena.Mostrar();
	cout << "\nMala mide: " << Mala.get_tam() << endl;
	Mala.Mostrar();

	return 0;
}
Y el error que me tira si creo los siguientes 5 archivos:
main.cpp, Nodo.cpp, Nodo.h, Lista.cpp y Lista.h
es:
Código:
$ g++ -c Nodo.cpp 
$ g++ -c Lista.cpp 
$ g++ main.cpp *.o
/tmp/ccNbYLWk.o: In function `main':
main.cpp:(.text+0x13): undefined reference to `Lista<int>::Lista()'
main.cpp:(.text+0x1f): undefined reference to `Lista<char>::Lista()'
main.cpp:(.text+0x39): undefined reference to `Lista<int>::add(int)'
main.cpp:(.text+0x59): undefined reference to `Lista<char>::add(char)'
main.cpp:(.text+0x6a): undefined reference to `Lista<char>::add(char)'
main.cpp:(.text+0x7b): undefined reference to `Lista<char>::add(char)'
main.cpp:(.text+0x8c): undefined reference to `Lista<char>::add(char)'
main.cpp:(.text+0x98): undefined reference to `Lista<int>::get_tam() const'
main.cpp:(.text+0xcc): undefined reference to `Lista<int>::Mostrar() const'
main.cpp:(.text+0xd8): undefined reference to `Lista<char>::get_tam() const'
main.cpp:(.text+0x10c): undefined reference to `Lista<char>::Mostrar() const'
main.cpp:(.text+0x11d): undefined reference to `Lista<char>::~Lista()'
main.cpp:(.text+0x130): undefined reference to `Lista<char>::~Lista()'
main.cpp:(.text+0x144): undefined reference to `Lista<int>::~Lista()'
main.cpp:(.text+0x160): undefined reference to `Lista<int>::~Lista()'
collect2: ld devolvió el estado de salida 1
$
¿Alguien me puede explicar que sucede?
  #2 (permalink)  
Antiguo 29/12/2010, 08:12
 
Fecha de Ingreso: abril-2010
Ubicación: Rosario
Mensajes: 1.850
Antigüedad: 14 años
Puntos: 228
Respuesta: Una Lista Enlazada con Plantillas en C++(duda)

Porque cuando lo tenes separado en el mail no tiene referencias sobre las clases que creaste... aunque los enlazes todos juntos, por separado minimamente tienen que estar las cabeceras.
Deberias hacer un archivo .h y agregarlo con el include en el main.
  #3 (permalink)  
Antiguo 30/12/2010, 00:31
 
Fecha de Ingreso: diciembre-2010
Mensajes: 4
Antigüedad: 13 años, 4 meses
Puntos: 0
Exclamación Respuesta: Una Lista Enlazada con Plantillas en C++(duda)

Cita:
Iniciado por sam90 Ver Mensaje
Porque cuando lo tenes separado en el mail no tiene referencias sobre las clases que creaste... aunque los enlazes todos juntos, por separado minimamente tienen que estar las cabeceras.
Deberias hacer un archivo .h y agregarlo con el include en el main.

No entiendo...
Eso es lo que hago al separar mis archivos...
Ademas si pongo todo en un .h no se podra precompilar ya que los .h no se compilan...
  #4 (permalink)  
Antiguo 30/12/2010, 06:31
 
Fecha de Ingreso: abril-2010
Ubicación: Rosario
Mensajes: 1.850
Antigüedad: 14 años
Puntos: 228
Respuesta: Una Lista Enlazada con Plantillas en C++(duda)

Solo debes poner la definiciones en el .h

Algo asi:

archivo.h
Código C++:
Ver original
  1. template <class Q>
  2. class Nodo{
  3.     private:
  4.         Q *MiDato;
  5.         Nodo<Q> *next;
  6.     public:
  7.         Nodo(Q nuevo);
  8.         Nodo(void): MiDato(NULL), next(NULL) ;
  9.         ~Nodo(void);
  10.         void set_data(Q nuevo);
  11.         void set_next(Nodo<Q> *s) ;
  12.         const Q get_data(void) const ;
  13.         Nodo<Q> *get_next(void) ;
  14.         void ShowAll(void) const;
  15. };

Luego en el main agregas:
#include "archivo.h"
  #5 (permalink)  
Antiguo 30/12/2010, 23:43
 
Fecha de Ingreso: febrero-2003
Ubicación: D.F.
Mensajes: 163
Antigüedad: 21 años, 2 meses
Puntos: 22
Respuesta: Una Lista Enlazada con Plantillas en C++(duda)

Los templates tienen un tratamiento especial por parte del compilador, lo recomendable es que tengas definido el template en un archivo de cabecera y no en un archivo que será traducido a código objeto (cpp) ya que se pierde generalidad. Obviamente esto último confunde un poco, ya que si algo buscamos justamente es ocultar la implementación del código que, aunque parezca absurdo en el caso de los templates, no lo es, todo dependerá de necesidades específicas.

Solución 1 (recomendable)
Nodo.h
Código C++:
Ver original
  1. #ifndef NODO_H
  2. #define NODO_H
  3. #include <iostream>
  4.  
  5. template <class Q>
  6. class Nodo{
  7.     private:
  8.         Q *MiDato;
  9.         Nodo<Q> *next;
  10.     public:
  11.         Nodo(Q nuevo){
  12.             next = NULL;
  13.             MiDato = new Q;
  14.             *MiDato = nuevo;
  15.         }
  16.         Nodo(void): MiDato(NULL), next(NULL) {}
  17.         ~Nodo(void){
  18.             delete MiDato;
  19.             next = NULL;
  20.         }
  21.         void set_data(Q nuevo){
  22.             MiDato = new Q;
  23.             *MiDato = nuevo;
  24.         }
  25.         void set_next(Nodo<Q> *s) { next = s; }
  26.         const Q get_data(void) const { return *MiDato; }
  27.         Nodo<Q> *get_next(void) { return next; }
  28.         void ShowAll(void) const{
  29.             Nodo<Q> *aux = next;
  30.  
  31.             std::cout << *MiDato << std::endl;
  32.             while(aux){
  33.                 std::cout << aux->get_data() << std::endl;
  34.                 aux = aux->get_next();
  35.             }
  36.         }
  37. };
  38.  
  39. #endif // NODO_H
Lista.h
Código C++:
Ver original
  1. #ifndef LISTA_H
  2. #define LISTA_H
  3.  
  4. #include "Nodo.h"
  5.  
  6. template <class Q>
  7. class Lista{
  8.     private:
  9.         Nodo<Q> *inicio;
  10.         Nodo<Q> *final;
  11.         int tam;
  12.     public:
  13.         Lista(void): inicio(NULL), final(NULL), tam(0) {}
  14.         ~Lista(void){
  15.             Nodo<Q> *aux = inicio;
  16.  
  17.             if(!empty()){
  18.                 while(inicio){
  19.                     inicio = inicio->get_next();
  20.                     delete aux;
  21.                     aux = inicio;
  22.                 }
  23.             }
  24.             final = NULL;
  25.             tam = 0;
  26.         }
  27.         void add(Q nuevo){
  28.             Nodo<Q> *aux = new Nodo<Q>(nuevo);
  29.             if(empty()){
  30.                 inicio = aux;
  31.             }else{
  32.                 final->set_next(aux);
  33.             }
  34.             final = aux;
  35.             tam++;
  36.         }
  37.         int get_tam(void) const { return tam; }
  38.         bool empty(void) const{
  39.             return (inicio == NULL);
  40.         }
  41.         void Mostrar(void) const { inicio->ShowAll(); }
  42. };
  43.  
  44.  
  45. #endif // LISTA_H
main.cpp
Código C++:
Ver original
  1. #include <iostream>
  2. #include "Lista.h"
  3. using namespace std;
  4.  
  5.  
  6. int main(void){
  7.     Lista<int> Buena;
  8.     Lista<char> Mala;
  9.  
  10.     for(int i = 10; i < 21; i++){
  11.         Buena.add(i);
  12.     }
  13.     Mala.add('M');
  14.     Mala.add('A');
  15.     Mala.add('L');
  16.     Mala.add('A');
  17.  
  18.     cout << "Buena mide: " << Buena.get_tam() << endl;
  19.     Buena.Mostrar();
  20.     cout << "\nMala mide: " << Mala.get_tam() << endl;
  21.     Mala.Mostrar();
  22.  
  23.     return 0;
  24. }

Solución 2
Nodo.h
Código C++:
Ver original
  1. #ifndef NODO_H
  2. #define NODO_H
  3.  
  4. template <class Q>
  5. class Nodo{
  6.     private:
  7.         Q *MiDato;
  8.         Nodo<Q> *next;
  9.     public:
  10.         Nodo(Q nuevo);
  11.         Nodo(void);
  12.         ~Nodo(void);
  13.         void set_data(Q nuevo);
  14.         void set_next(Nodo<Q> *s);
  15.         const Q get_data(void) const;
  16.         Nodo<Q> *get_next(void);
  17.         void ShowAll(void) const;
  18. };
  19.  
  20. #endif // NODO_H
Nodo.cpp
Código C++:
Ver original
  1. #include <iostream>
  2. #include "Nodo.h"
  3. using namespace std;
  4.  
  5.  
  6. template <class Q>
  7. Nodo<Q>::Nodo(Q nuevo){
  8.     next = NULL;
  9.     MiDato = new Q;
  10.     *MiDato = nuevo;
  11. }
  12.  
  13. template <class Q>
  14. Nodo<Q>::Nodo(void): MiDato(NULL), next(NULL) {}
  15.  
  16. template <class Q>
  17. Nodo<Q>::~Nodo(void){
  18.     delete MiDato;
  19.     next = NULL;
  20. }
  21.  
  22. template <class Q>
  23. void Nodo<Q>::set_data(Q nuevo){
  24.     MiDato = new Q;
  25.     *MiDato = nuevo;
  26. }
  27.  
  28. template <class Q>
  29. void Nodo<Q>::set_next(Nodo<Q> *s) { next = s; }
  30.  
  31. template <class Q>
  32. const Q Nodo<Q>::get_data(void) const { return *MiDato; }
  33.  
  34. template <class Q>
  35. Nodo<Q> *Nodo<Q>::get_next(void) { return next; }
  36.  
  37.  
  38. template <class Q>
  39. void Nodo<Q>::ShowAll(void) const{
  40.     Nodo<Q> *aux = next;
  41.  
  42.     cout << *MiDato << endl;
  43.     while(aux){
  44.         cout << aux->get_data() << endl;
  45.         aux = aux->get_next();
  46.     }
  47. }
  48.  
  49.  
  50. template class Nodo<int>;
  51. template class Nodo<char>;
Lista.h
Código C++:
Ver original
  1. #ifndef LISTA_H
  2. #define LISTA_H
  3. #include "Nodo.h"
  4.  
  5. template <class Q>
  6. class Lista{
  7.     private:
  8.         Nodo<Q> *inicio;
  9.         Nodo<Q> *final;
  10.         int tam;
  11.     public:
  12.         Lista(void);
  13.         ~Lista(void);
  14.         void add(Q nuevo);
  15.         int get_tam(void) const;
  16.         bool empty(void) const;
  17.         void Mostrar(void) const;
  18. };
  19.  
  20. #endif // LISTA_H
Lista.cpp
Código C++:
Ver original
  1. #include <iostream>
  2. #include "Lista.h"
  3.  
  4. template <class Q>
  5. Lista<Q>::Lista(void): inicio(NULL), final(NULL), tam(0) {}
  6.  
  7. template <class Q>
  8. Lista<Q>::~Lista(void){
  9.     Nodo<Q> *aux = inicio;
  10.  
  11.     if(!empty()){
  12.         while(inicio){
  13.             inicio = inicio->get_next();
  14.             delete aux;
  15.             aux = inicio;
  16.         }
  17.     }
  18.     final = NULL;
  19.     tam = 0;
  20. }
  21.  
  22. template <class Q>
  23. void Lista<Q>::add(Q nuevo){
  24.     Nodo<Q> *aux = new Nodo<Q>(nuevo);
  25.     if(empty()){
  26.         inicio = aux;
  27.     }else{
  28.         final->set_next(aux);
  29.     }
  30.     final = aux;
  31.     tam++;
  32. }
  33.  
  34. template <class Q>
  35. int Lista<Q>::get_tam(void) const { return tam; }
  36.  
  37. template <class Q>
  38. bool Lista<Q>::empty(void) const{
  39.     return (inicio == NULL);
  40. }
  41.  
  42. template <class Q>
  43. void Lista<Q>::Mostrar(void) const { inicio->ShowAll(); }
  44.  
  45.  
  46. template class Lista<int>;
  47. template class Lista<char>;
main.cpp
Código C++:
Ver original
  1. #include <iostream>
  2. #include "Lista.h"
  3. using namespace std;
  4.  
  5.  
  6. int main(void){
  7.     Lista<int> Buena;
  8.     Lista<char> Mala;
  9.  
  10.     for(int i = 10; i < 21; i++){
  11.         Buena.add(i);
  12.     }
  13.     Mala.add('M');
  14.     Mala.add('A');
  15.     Mala.add('L');
  16.     Mala.add('A');
  17.  
  18.     cout << "Buena mide: " << Buena.get_tam() << endl;
  19.     Buena.Mostrar();
  20.     cout << "\nMala mide: " << Mala.get_tam() << endl;
  21.     Mala.Mostrar();
  22.  
  23.     return 0;
  24. }

Puedes consultar el siguiente tema para entender la implementación de la solución 2.

Etiquetas: c++, enlazada, generica, lista, plantillas
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 17:10.