C/Visual C - Clases plantilla en c++

 
Vista:

Clases plantilla en c++

Publicado por Mcquade (3 intervenciones) el 20/08/2002 15:58:36
Hola: Estoy haciendo un programa con Visual C++. En dicho programa he creado una nueva clase, que es una plantilla para crear arrays de cualquier tipo. Dentro del programa principal he incluido la clase mediante: #include "plantilla.h" Despues he declarado una variable: plantilla<int> nuevoarray(5); Al compilar no me da errores, pero al linkar me da un error para cada llamada a un metodo de la plantilla. El error es: error LNK2001: unresolved external symbol "public: virtual __thiscall plantilla<int>::~plantilla<int>(void)" (??1?$plantilla@H@@UAE@XZ) En cambio si meto todo el codigo de la clase dentro del programa principal me funciona perfectamente,¿que hago mal?
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

RE:Clases plantilla en c++

Publicado por El Mogur (202 intervenciones) el 20/08/2002 19:53:28
A mi entender, no haces nada mal. Es un problema con los templates que trae de cabeza a todo el mundo al principio...
Cuando el compilador encuentra en el código del programa principal el "plantilla<int>", no da error al compilar porque has incluido la cabecera, y en el momento de la compilación, el compilador supone que las funciones a las que llamas, con el tipo int instanciado para la plantilla están en algún otro sitio... y como en realidad no lo están, da error al linkar.

Lo que hay que hacer es poner todo el código de la plantilla en el fichero plantilla.h, en vez de tener un fichero de cabecera y otro de implementación.
De esta forma, cuando el compilador encuentra la definición, crea el código necesario para el tipo plantilla con el tipo int instanciado, y luego el enlazador encontrará el código, y todo funcionará.
Esto podría hacerte pensar que en caso de utilizar el mismo plantilla<int> en dos ficheros de código fuente distinto, se generará el código máquina dos veces, y luego aparecerá repetido en el ejecutable, haciendolo más grande... Pero no; si el enlazador es lo suficientemente bueno o moderno (y el del VC++ creo que lo es), lo detecta y solo mete una copia en el ejecutable final.

Espero haberme explicado medianamente, y que te sirva.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Pregunta para el Mogur

Publicado por chuidiang (677 intervenciones) el 20/08/2002 21:26:10
Buenas:
Me he encontrado con el problema de los templates y lo he solucionado como dices, pero no me acaba de convencer.

Cuando dices meter el codigo de la plantilla en el .h, ¿cómo lo metes?

¿Asi?
template <...>
class A {
{
void funcion() { codigo ...; }
}

o asi?
template <...>
class A {
void funcion();
}

void A::funcion()
{
}

En el primer caso funciona todo bien, pero la función es inline, es decir, en realidad no es una función, sino que el compilador escribe el código cada vez que se llama a la función (algo así como si fuera una macro).
En el segundo caso, si hago include de la plantilla en dos modulos distintos, al linkar me da error de que el código de la función está repetido.
Tengo que meterme un poco en serio con el tema, pero si me puedes contestar seguro que me ahorras unas horitas de trabajo.
Se bueno.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Pregunta para el Mogur

Publicado por El Mogur (202 intervenciones) el 21/08/2002 20:53:47
Tienes razón en que si metes la función en el .h la función es inline, y el compilador intentará meterla directamente en el código de la función desde la que se invoca (aunque eso no hace que eso no sea un función). De todas formas, si la función es demasiado larga, el compilador olvida el inline, y se convierte en una función normal.

El problema de los templates es a la hora de compilar. En realidad cuando defines el código de un template en C++, el compilador NO CREA CODIGO MAQUINA hasta que no se necesita. Por tanto, si el fuente lo tienes en un fichero .CPP, y generas el .OBJ, no se va a crear nada.
Entonces, en otro fichero distinto incluyes el .h con tus definiciones, y cuando das a compilar, el compilador se lo traga, porque las definiciones están bien, pero a la hora de linkar, hay error, porque no se ha generado el código máquina para tu instanciación particular sustituyendo el tipo template por el tuyo particular.
¿Solución? Meter el código en el .h (como funciones inline). Esa es la solución adoptada en el código fuente de la librería standar de C++ (las STL). De esta forma, cuando el compilador en tu código ve el uso de la clase con un tipo determinado (la instanciación), al tener el código (en la cabecera que has incluido), crea el código máquina en el fichero OBJ de la unidad que lo utiliza, y no da problemas al linkar.
Resumiendo:
--- Fichero miTemplate.h ---
template <class T> class A {
void miFuncion() {...};
}

-- Fichero usoElTemplate.cpp --
#include <miTemplate.h>
A<int> miVble;
...

En el fichero objeto usoElTemplate.obj, aparecerá el c%
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Pregunta para el Mogur

Publicado por chuidiang (677 intervenciones) el 21/08/2002 21:35:07
Aclarado, muchas gracias.

Habitualmente uso el compilador de Solaris (Unix). Ellos lo resuelven haciendo que el compilador cree una especie de base de datos de contenido misterioso (Templates.DB) con los códigos de las funciones template que están en el .cpp. Luego, el linkador, lee esa base de datos junto con los .obj habituales y es capaz de generar el ejecutable sin problemas.

Actualmente estoy intentando pasar el código a linux y me he encontrado el problema que te comenté con los templates (no genera nada parecido al Templates.DB). Lo de la función inline es la solución a la que había llegado, pero no me acababa de convencer. Si me dices que la STL lo hace así, no quedará más remedio que tragar.

Gracias de nuevo y se bueno.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar