Error con Templates

25/11/2003 - 18:12 por jose | Informe spam
Hola grupo,

Estoy creando una clase basada en otra que utiliza templates y me aparece
el siguiente error al linkar (no encuentra el constructor ni el
destructor de la clase con templates):

TADTreeCompraTipo.obj : error LNK2001: unresolved external symbol
"public: __thiscall CTreeDinamic<class CCompraTipo>::CTreeDinamic<class
CCompraTipo>(void)" (??0?$CTreeDinamic@VCCompraTipo@@@@QAE@XZ)

TADTreeCompraTipo.obj : error LNK2001: unresolved external symbol
"public: __thiscall CTreeDinamic<class CCompraTipo>::~CTreeDinamic<class
CCompraTipo>(void)" (??1?$CTreeDinamic@VCCompraTipo@@@@QAE@XZ)

Lo curioso es que tengo incluido el fichero donde está definido
CTreeDinamic (la clase con templates).

¿Alguna idea o sugerencia?

Muchas gracias,

Jose

Preguntas similare

Leer las respuestas

#1 KAKATUO
25/11/2003 - 19:20 | Informe spam
Hola jose,
¿Puedes postear algún ejemplo de tu código para que podamos compilarlo
nosotros?

Saludos

"jose" escribió en el mensaje
news:
Hola grupo,

Estoy creando una clase basada en otra que utiliza templates y me aparece
el siguiente error al linkar (no encuentra el constructor ni el
destructor de la clase con templates):

TADTreeCompraTipo.obj : error LNK2001: unresolved external symbol
"public: __thiscall CTreeDinamic<class CCompraTipo>::CTreeDinamic<class
CCompraTipo>(void)" (??0?$@@@@)

TADTreeCompraTipo.obj : error LNK2001: unresolved external symbol
"public: __thiscall CTreeDinamic<class CCompraTipo>::~CTreeDinamic<class
CCompraTipo>(void)" (??1?$@@@@)

Lo curioso es que tengo incluido el fichero donde está definido
CTreeDinamic (la clase con templates).

¿Alguna idea o sugerencia?

Muchas gracias,

Jose
Respuesta Responder a este mensaje
#2 jose
25/11/2003 - 20:19 | Informe spam
Hola,

Estoy intentando reproducir el error con un ejemplo sencillo (el código es
bastante complejo), espero poder postearlo mañana.

Un saludo,

Jose

"KAKATUO" wrote in
news:bq06gq$ua1$02$:

Hola jose,
¿Puedes postear algún ejemplo de tu código para que podamos compilarlo
nosotros?

Saludos
Respuesta Responder a este mensaje
#3 jose
25/11/2003 - 21:14 | Informe spam
Es un poco largo...


<BEGIN>"Vitual2.h"-

#ifndef _TREE_DINAMIC_2
#define _TREE_DINAMIC_2


template<class TYPE>
class CNodoDinamicTree{
public:
int m_nId;
TYPE m_Informacion;
CNodoDinamicTree<TYPE> *m_pArrayNodos[2];
public:
CNodoDinamicTree();
~CNodoDinamicTree();
};


template<class TYPE>
class CDinamicTree{
int m_nNodos;
CNodoDinamicTree<TYPE> *m_pArrayNodos[2];
public:
CDinamicTree();
~CDinamicTree();


bool InsertarHijo(int nId, TYPE &t);
CNodoDinamicTree<TYPE> *ObtenerNodo(int nIndex);

};


#endif // _TREE_DINAMIC_2




<END>"Vitual2.h"-




<BEGIN>"Vitual2.cpp"-

#include "StdAfx.h"


#include "Virtual2.h"



template<class TYPE>
bool CDinamicTree<TYPE>::InsertarHijo(int nId, TYPE &t)
{
*pNodo = new CNodoDinamicTree<TYPE>;
if(!*pNodo) return false;
*pNodo->m_nId = nId;
*pNodo->m_Informacion = t;
*pNodo->m_pArrayNodos[0] = NULL;
*pNodo->m_pArrayNodos[1] = NULL;
return true;
}

template<class TYPE>
CNodoDinamicTree<TYPE> *CDinamicTree<TYPE>::ObtenerNodo(int i)
{
if(i < 0 || i > m_nNodos) return NULL;
return m_TreeCompraTipo[i];
}


<END>"Vitual2.cpp"-






<BEGIN>"Vitual3.h"-

#ifndef _TREE_DINAMIC_3
#define _TREE_DINAMIC_3



#include "Virtual2.h"


class CCompraTipo{
public:
int nPases;
double dPrecio;
public:
CCompraTipo(){};
~CCompraTipo(){};
// Constructor de copia
CCompraTipo( const CCompraTipo &a){
nPases = a.nPases;
dPrecio = a.dPrecio;
};
// Operador de copia
CCompraTipo &CCompraTipo::operator=( const CCompraTipo &a)
{
nPases = a.nPases;
dPrecio = a.dPrecio;
return *this;
}
};

class CTADTreeCompraTipo{
private:
CDinamicTree<CCompraTipo> m_TreeCompraTipo;
public:
CTADTreeCompraTipo();
~CTADTreeCompraTipo();
};

#endif // _TREE_DINAMIC_3


<END>"Vitual3.h"-

<BEGIN>"en donde se prefiera (main por ej.)"-

#include "Virtual3.h"


int main(int argc, char* argv[])
{

CDinamicTree<CCompraTipo> m_Prueba;
return 0;
}



<END>"en donde se prefiera (main por ej.)"-



Muchas gracias,

Jose





"KAKATUO" wrote in
news:bq06gq$ua1$02$:

Hola jose,
¿Puedes postear algún ejemplo de tu código para que podamos compilarlo
nosotros?

Saludos

"jose" escribió en el mensaje
news:
Hola grupo,

Estoy creando una clase basada en otra que utiliza templates y me
aparece el siguiente error al linkar (no encuentra el constructor ni
el destructor de la clase con templates):

TADTreeCompraTipo.obj : error LNK2001: unresolved external symbol
"public: __thiscall CTreeDinamic<class
CCompraTipo>::CTreeDinamic<class CCompraTipo>(void)"
(??0?$@@@@)

TADTreeCompraTipo.obj : error LNK2001: unresolved external symbol
"public: __thiscall CTreeDinamic<class
CCompraTipo>::~CTreeDinamic<class CCompraTipo>(void)"
(??1?$@@@@)

Lo curioso es que tengo incluido el fichero donde está definido
CTreeDinamic (la clase con templates).

¿Alguna idea o sugerencia?

Muchas gracias,

Jose




Respuesta Responder a este mensaje
#4 KAKATUO
25/11/2003 - 23:06 | Informe spam
Me parece que el error está en que para utilizar clases de plantilla se debe
incluir no solo la declaración de la clase sino también su implementación en
los ficheros que la utilizan.
El compilador no compila una clase de plantilla hasta que no se instancian
las clases variables que la definen.
En tu caso debes incluir la definicióan de todas las funciones miembro
(incluidas las del constructor y el destructor que se te han olvidado) de
CDinamicTree y CNodoDinamic en el fichero de cabecera Virtual2.h para que
estén presentes en el momento de la compilación.
También puedes incluir el fichero virtual2.cpp en virtual3.cpp pero esto no
es muy ortodoxo.
otra solución es crear toda la clase de plantilla en un fichero virtual2.hpp
o virtual2.cxx e incluirlo en virtual3.cpp.

No se si me he explicado bien.

Saludos


"jose" escribió en el mensaje
news:
Es un poco largo...


<BEGIN>"Vitual2.h"-

#ifndef _TREE_DINAMIC_2
#define _TREE_DINAMIC_2


template<class TYPE>
class CNodoDinamicTree{
public:
int m_nId;
TYPE m_Informacion;
CNodoDinamicTree<TYPE> *m_pArrayNodos[2];
public:
CNodoDinamicTree();
~CNodoDinamicTree();
};


template<class TYPE>
class CDinamicTree{
int m_nNodos;
CNodoDinamicTree<TYPE> *m_pArrayNodos[2];
public:
CDinamicTree();
~CDinamicTree();


bool InsertarHijo(int nId, TYPE &t);
CNodoDinamicTree<TYPE> *ObtenerNodo(int nIndex);

};


#endif // _TREE_DINAMIC_2




<END>"Vitual2.h"-




<BEGIN>"Vitual2.cpp"-

#include "StdAfx.h"


#include "Virtual2.h"



template<class TYPE>
bool CDinamicTree<TYPE>::InsertarHijo(int nId, TYPE &t)
{
*pNodo = new CNodoDinamicTree<TYPE>;
if(!*pNodo) return false;
*pNodo->m_nId = nId;
*pNodo->m_Informacion = t;
*pNodo->m_pArrayNodos[0] = NULL;
*pNodo->m_pArrayNodos[1] = NULL;
return true;
}

template<class TYPE>
CNodoDinamicTree<TYPE> *CDinamicTree<TYPE>::ObtenerNodo(int i)
{
if(i < 0 || i > m_nNodos) return NULL;
return m_TreeCompraTipo[i];
}


<END>"Vitual2.cpp"-






<BEGIN>"Vitual3.h"-

#ifndef _TREE_DINAMIC_3
#define _TREE_DINAMIC_3



#include "Virtual2.h"


class CCompraTipo{
public:
int nPases;
double dPrecio;
public:
CCompraTipo(){};
~CCompraTipo(){};
// Constructor de copia
CCompraTipo( const CCompraTipo &a){
nPases = a.nPases;
dPrecio = a.dPrecio;
};
// Operador de copia
CCompraTipo &CCompraTipo::operator=( const CCompraTipo &a)
{
nPases = a.nPases;
dPrecio = a.dPrecio;
return *this;
}
};

class CTADTreeCompraTipo{
private:
CDinamicTree<CCompraTipo> m_TreeCompraTipo;
public:
CTADTreeCompraTipo();
~CTADTreeCompraTipo();
};

#endif // _TREE_DINAMIC_3


<END>"Vitual3.h"-

<BEGIN>"en donde se prefiera (main por ej.)"-

#include "Virtual3.h"


int main(int argc, char* argv[])
{

CDinamicTree<CCompraTipo> m_Prueba;
return 0;
}



<END>"en donde se prefiera (main por ej.)"-



Muchas gracias,

Jose





"KAKATUO" wrote in
news:bq06gq$ua1$02$:

> Hola jose,
> ¿Puedes postear algún ejemplo de tu código para que podamos compilarlo
> nosotros?
>
> Saludos
>
> "jose" escribió en el mensaje
> news:
>> Hola grupo,
>>
>> Estoy creando una clase basada en otra que utiliza templates y me
>> aparece el siguiente error al linkar (no encuentra el constructor ni
>> el destructor de la clase con templates):
>>
>> TADTreeCompraTipo.obj : error LNK2001: unresolved external symbol
>> "public: __thiscall CTreeDinamic<class
>> CCompraTipo>::CTreeDinamic<class CCompraTipo>(void)"
>> (??0?$@@@@)
>>
>> TADTreeCompraTipo.obj : error LNK2001: unresolved external symbol
>> "public: __thiscall CTreeDinamic<class
>> CCompraTipo>::~CTreeDinamic<class CCompraTipo>(void)"
>> (??1?$@@@@)
>>
>> Lo curioso es que tengo incluido el fichero donde está definido
>> CTreeDinamic (la clase con templates).
>>
>> ¿Alguna idea o sugerencia?
>>
>> Muchas gracias,
>>
>> Jose
>
>

Respuesta Responder a este mensaje
#5 jose
26/11/2003 - 12:22 | Informe spam
Muchas gracias,

He corregido el problema incluyendo todo el código del .cpp de las clases
con templates dentro de sus .h

He encontrado esta pequeña explicación en el libro
"Thinking in C++, 2nd ed. Volume 1", 2000 by Bruce Eckel

Header files

Even if you create non-inline function definitions, you’ll usually want
to put all declarations and definitions for a template into a header
file. This may seem to violate the normal header file rule of "Don’t put
in anything that allocates storage," (which prevents multiple definition
errors at link time), but template definitions are special. Anything
preceded by template<...> means the compiler won’t allocate storage for
it at that point, but will instead wait until it’s told to (by a template
instantiation), and that somewhere in the compiler and linker there’s a
mechanism for removing multiple definitions of an identical template. So
you’ll almost always put the entire template declaration and definition
in the header file, for ease of use.


There are times when you may need to place the template definitions in a
separate cpp file to satisfy special needs (for example, forcing template
instantiations to exist in only a single Windows dll file). Most
compilers have some mechanism to allow this; you’ll have to investigate
your particular compiler’s documentation to use it.


Reitero las gracias.
Un saludo,

Jose


"KAKATUO" wrote in
news:bq0joo$npu$00$:

Me parece que el error está en que para utilizar clases de plantilla
se debe incluir no solo la declaración de la clase sino también su
implementación en los ficheros que la utilizan.
El compilador no compila una clase de plantilla hasta que no se
instancian las clases variables que la definen.
En tu caso debes incluir la definicióan de todas las funciones miembro
(incluidas las del constructor y el destructor que se te han olvidado)
de CDinamicTree y CNodoDinamic en el fichero de cabecera Virtual2.h
para que estén presentes en el momento de la compilación.
También puedes incluir el fichero virtual2.cpp en virtual3.cpp pero
esto no es muy ortodoxo.
otra solución es crear toda la clase de plantilla en un fichero
virtual2.hpp o virtual2.cxx e incluirlo en virtual3.cpp.

No se si me he explicado bien.

Saludos


email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaRespuesta Tengo una respuesta
Search Busqueda sugerida