Foros del Web » Programación para mayores de 30 ;) » iOs »

Llamar métodos heredados de una clase template

Estas en el tema de Llamar métodos heredados de una clase template en el foro de iOs en Foros del Web. Hola a todos. Les planteo el escenario, simplificado. Tengo una clase A. Luego, una clase template B que hereda de A. Por último, tengo una ...
  #1 (permalink)  
Antiguo 01/12/2010, 15:53
 
Fecha de Ingreso: marzo-2005
Mensajes: 1.418
Antigüedad: 19 años
Puntos: 9
Llamar métodos heredados de una clase template

Hola a todos.
Les planteo el escenario, simplificado. Tengo una clase A. Luego, una clase template B que hereda de A. Por último, tengo una clase C que hereda de B, pero C la defino como:

Código C++:
Ver original
  1. class C : public B<AlgunTipo>
  2. {
  3.     //Declaración de la interface
  4. };

Además, los métodos de B los defino en un archivo separado (.mm ya que estoy desarrollando para iPhone) de la forma template<class T> void B<T>::unMetodo(...).

Resulta que si intento llamar a un método de C, pero que esté definido en B (es decir, un método heredado de B), el compilador me dice "undefined symbol" y me da la lista de lugares desde donde se hace referencia al método.
Ya he leído varios tutoriales acerca de templates y según creo de acuerdo a lo que he leído la sintaxis es correcta.
¿Alguna idea por qué el compilador no me está detectando esos métodos?.

Gracias por adelantado.
__________________
Add, never Remove
  #2 (permalink)  
Antiguo 01/12/2010, 16:58
 
Fecha de Ingreso: marzo-2005
Mensajes: 1.418
Antigüedad: 19 años
Puntos: 9
Respuesta: Llamar métodos heredados de una clase template

Pude regenerar el problema para hacerlo más entendible en dev-c++, con código y corto:

BoardBase.h
Código C++:
Ver original
  1. template<class T>
  2. class BoardBase
  3. {
  4.     T value;
  5.    
  6.     public:
  7.     void print();
  8. };

BoardBase.cpp
Código C++:
Ver original
  1. #include "BoardBase.h"
  2. #include <iostream>
  3.  
  4. template<class T> void BoardBase<T>::print()
  5. {
  6.     cout << "Probando print" << endl;
  7. }

Board.h
Código C++:
Ver original
  1. #include "BoardBase.h"
  2.  
  3. class Board : public BoardBase<int>
  4. {
  5.     public:
  6.     void printDerived();
  7. };

Board.cpp
Código C++:
Ver original
  1. #include "Board.h"
  2. #include <iostream>
  3. void Board::printDerived()
  4. {
  5.     cout << "Probando printDerived" << endl;
  6. }

Si en el main llamo a printDerived() todo funciona correctamente. Sin embargo, si llamo a print(), ahora en Dev-C++, me sale el error [Linker error] undefined reference to `BoardBase<int>::print(void)' . Si bien los mensajes no son iguales, el error es equivalente al que obtengo en el compilador para iPhone.
__________________
Add, never Remove
  #3 (permalink)  
Antiguo 03/12/2010, 17:02
 
Fecha de Ingreso: febrero-2003
Ubicación: D.F.
Mensajes: 163
Antigüedad: 21 años, 2 meses
Puntos: 22
Respuesta: Llamar métodos heredados de una clase template

Voy a suponer que la función main se encuentra en un archivo main.cpp, hasta aquí tienes 3 archivos que serán traducidos a código objeto por el compilador; esto es: main.cpp, Board.cpp y BoardBase.cpp. Pues bien, al momento de compilar main.cpp el compilador trata de crear una instancia para BoardBase<int>::print(), pero solo logra ver la declaración del template y no su definición puesto que se encuentra en otra unidad de código (BoardBase.cpp), por lo que no se genera dicha instancia. Entonces, cuando el enlazador(linker) busca la definición de la función en las diferentes unidades de código objeto tampoco la encuentra, porque solo se tiene la definición del template en BoardBase.cpp y no hay ningún código que le indique al compilador que haya que crear una instancia de BoardBase<int>::print() , luego entonces no la encuentra y se muestra el error. Recuerda que tu defines los templates y el compilador se encarga de crear las instancias necesarias. La buena, es que también podemos crear instancias de forma explícita.

Para este caso tienes 2 soluciones:

1. Te basta con mover la definición a su archivo de cabecera (olvidate de BoardBase.cpp), es común que tengas tanto declaraciones como definiciones de templates en los archivos de cabecera.

BoardBase.h
Código C++:
Ver original
  1. #ifndef BOARDBASE_H
  2. #define BOARDBASE_H
  3. #include <iostream>
  4.  
  5. template<class T>
  6. class BoardBase
  7. {
  8.     T value;
  9.    
  10.     public:
  11.     void print();
  12. };
  13.  
  14. template<class T> void BoardBase<T>::print()
  15. {
  16.     std::cout << "Probando print" << std::endl;
  17. }
  18.  
  19. #endif // BOARDBASE_H

2. Crear una instancia para BoardBase<int>::print() de forma explícita en BoardBase.cpp

BoardBase.cpp

Código C++:
Ver original
  1. #include "BoardBase.h"
  2. #include <iostream>
  3. using namespace std;
  4.  
  5. template<class T> void BoardBase<T>::print()
  6. {
  7.     cout << "Probando print" << endl;
  8. }
  9.  
  10.  
  11. template void BoardBase<int>::print();
  12. // o tambien puedes usar:  template BoardBase<int>;
Observa la declaración seguida de la palabra "template". De hecho puedes crear una instancia para la clase completa y no solo para un método, pero podrías estar creando instancias de métodos que resulten innecesarias, pros y contras, pero bueno.

Por último, ten cuidado con el namespace std para cout y endl, y la otra utiliza las directivas #ifndef y #define del preprocesador para evitar inclusiones múltiples de tus archivos de cabecera.

Etiquetas: clase, llamar, template
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 06:27.