Clases genéricas
Ejemplo
Se presenta una variación sintáctica de una clase genérica utilizada en un caso anterior
( Ejemplo-2). En este caso, la
definición de todas las funciones-miembro se han realizado fuera del cuerpo de la clase (off-line).
Se muestra como estas funciones deben ser definidas explícitamente
como funciones genéricas (
4.12.1), y como debe utilizarse el parámetro <T> en todas las ocurrencias del identificador
mVector (caso de las definiciones del operador de asignación, constructor-copia, etc).
Recordemos que si mVector es una clase genérica, el identificador mVector debe ir acompañado siempre por un tipo entre los símbolos < > (excepto dentro del cuerpo de la clase, en cuyo caso es redundante).
class Vector { // clase auxiliar
public: int x, y;
Vector& operator= (const Vector& v) {
x = v.x; y = v.y;
return *this;
}
void showV() { cout << "X = " << x << "; Y = " << y << endl; }
};
template<class T> class mVector { // definición de plantilla mVector
int dimension;
public:
T* mVptr;
mVector& operator= (const mVector&); // operador de asignación
mVector(int);
// constructor por defecto
~mVector();
// destructor
mVector(const mVector<T>& mv); // constructor-copia
T& operator[](int i) { return mVptr[i]; }
void showmem (int);
// función auxiliar
void show ();
// función auxiliar
};
// operador de asignación ======
template<class T> mVector<T>& mVector<T>::operator=(const mVector<T>& mv) {
delete [] mVptr;
dimension = mv.dimension;
mVptr = new T[dimension];
for(int i = 0; i<dimension; i++) {
mVptr[i]= mv.mVptr[i];
}
return *this;
}
// Constructor por defecto ======
template<class T> mVector<T>::mVector(int n = 1) {
dimension = n;
mVptr = new T[dimension];
}
// Destructor ===================
template <class T> mVector<T>::~mVector() {
delete [] mVptr;
}
// Constructor-copia ============
template <class T> mVector<T>::mVector(const mVector<T>& mv) {
dimension = mv.dimension;
mVptr = new T[dimension];
for(int i = 0; i<dimension; i++) {
mVptr[i]= mv.mVptr[i];
}
}
// Función auxiliar =============
template <class T> void mVector<T>::showmem (int i) {
if((i >= 0) && (i <= dimension)) mVptr[i].showV();
else cout << "Argumento incorrecto! pruebe otra vez" << endl;
}
// Función auxiliar =============
template <class T> void mVector<T>::show () {
cout << "Matriz de: " << dimension << " elementos." << endl;
for (int i = 0; i<dimension; i++) {
cout << i << "- ";
mVptr[i].showV();
}
}
void main() { // =====================
mVector<Vector> mV1 = mVector<Vector>(5); // M.1
mV1[0].x = 0; mV1[0].y = 1;
mV1[1].x = 2; mV1[1].y = 3;
mV1[2].x = 4; mV1[2].y = 5;
mV1[3].x = 6; mV1[3].y = 7;
mV1[4].x = 8; mV1[4].y = 9;
mV1.show();
mVector<Vector> mV2 = mV1;
// M.8
mV2.show();
mV1[0].x = 9; mV1[0].y = 0;
mV2.showmem(0);
mV1.showmem(0);
mVector<Vector> mV3 = mVector<Vector>(0); // M.13
mV3.show();
mV3 = mV1; mV3.show();
}
La salida es exactamente la misma que en el ejemplo tomado como modelo
, al que nos referimos para cualquier consulta al
respecto.
Comentario
Aparte de las modificaciones introducidas en la definición de la plantilla mVector, donde las definiciones de las funciones-miembro se han sacado fuera (off-line), se ha modificado ligeramente la sintaxis de las sentencias M.1 y M.13, en el sentido de que ahora contienen una invocación explícita al constructor de la clase, y puede comprobarse como cada invocación a mVector debe ir acompañado siempre por un argumento.