4.12.2a Clases genricas II1 Las clases genricas y la organizacin
del cdigoPara la organizacin de las plantillas de clases genricas
pueden utilizarse las mismas pautas indicada para las funciones
genricas (4.12.1b): Fichero nico. Fichero combinado. Ficheros
mltiples (compilacin separada).
1.1 El mtodo defichero nicoexige que el compilador encuentre la
definicin de las plantillas antes de su uso en cada unidad de
compilacin. Presenta el inconveniente de que las plantillas
definidas en un mdulo no son visibles desde los dems. Responde al
siguiente esquema:template class C1 { // declaracin/definicin ...
// definicion...};...int main() { ... C1 c1; // uso de una
instancia ...}
1.2 El mtodo defichero combinadoconsiste en situar en un fichero
de cabecera las definiciones de todas las clases genricas (y de sus
funciones-miembro). Posteriormente este fichero es incluido en
todos los mdulos que utilicen la clase genrica. La situacin queda
esquematizada como sigue://cabecera.h#ifndef PLT_1#define PLT_1
template class C1 { // declaracin ... // definicion... };#endif //
PLT_1...// main.cpp#include ...int main() { ... C1 c1; ...}
// modulo-1.cpp#include ...{ ... C1 ch; ...}//
modulo-2.cpp#include ...{ ... C1 cx; ...}
De esta forma se garantiza que la plantilla pueda ser utilizada
por ms de una unidad de compilacin.
1.3 El mtodo decompilacin separadaconsiste en incluir en un
fichero de cabecera las declaraciones de las clases genricas, e
incluir este fichero en todos los mdulos de compilacin mediante la
oportuna directiva#include. Las definiciones off-line de todos los
mtodos van precedidas de la directivaexport, y se incluyen en un
fichero que es compilado separadamente://cabecera.h#ifndef
C_1#define C_1 template class C1 { // declaracin void C1::f1();
void C1::f2();... };#endif // C_1...// definiciones.cpp#include
...export template void C1::f1() { ... // definicin 1}export
template void C1::f2() { ... // definicin 2}...
// modulo-1.cpp#include ...{ ... C1 n1; ...}...//
modulo-2.cpp#include ...{ ... C1 cx; ...}...
Desafortunadamente, a la fecha ninguno de los compiladores que
hemos utilizado para plataformas PC incluye soporte para el
especificadorexporten estas condiciones [1].2El
especificadorfriendcon funciones genricasRecordemos quefriendes un
especificador de acceso, utilizado para declarar que ciertas
funciones o clases (que denominamos "invitadas") tienen acceso al
mbito de ciertas clases "anfitrionas" (4.11.2a1). En el captulo
correspondiente se explicaron sus caractersticas y las indicaciones
pertinentes sobre su uso. Sin embargo, cuando las funcionesfriendde
una clase son a su vez funciones genricas ("templates"), su
utilizacin requiere algunas cauciones particulares.Para empezar,
debemos recordar que los "invitados" (friend) de una clase
ordinaria o genrica (plantilla), pueden ser: una funcin, o una
clase ordinarias (no genricas); una funcin genrica ("template); una
clase genrica; la especializacin de una funcin genrica, y la
especializacin de una clase genrica [2].Recordemostambin, que
cuando la clase anfitriona es una clase genrica (plantilla), sus
propiedades y mtodos son a su vez clases genricas (4.12.2). Como es
usual, en estos casos la declaracin de tales mtodos debe hacerse en
el cuerpo de la clase genrica, mientras que la definicin puede
hacerse dentro (on-line) o fuera (off-line), a continuacin de la
anterior. Es el caso esquematizado a continuacin, en el que
suponemos una claseArraydestinada a almacenar matrices
unidimensionales de elementos de tipo numrico
(int,float,long,float*, etc).template class Array { // clase
genrica public: Array(); // constructor por defecto Array&
operator= (const Array&); // operador de asignacin ...};
template Array::Array() // definicion del constructor /* alguna
funcin de T ... */}
template Array& Array::operator= (const Array& ar) { /*
alguna funcin de T ... */ ... return *this;}En este ejemplo, tanto
el constructor por defecto como el operador de asignacin, se han
definido off-line a continuacin del cuerpo de la clase; exactamente
igual que en una clase ordinaria, aunque teniendo en cuenta que en
esta ocasin, ambos mtodos son a su vez funciones genricas. En
realidad, cualquiera que sea la forma de su definicin (on-line u
off-line), ambos mtodos estn en el mbito de la clase y pertenecen a
ella. Cuando se obtiene una especializacin de la clase genrica. Por
ejemplo:Array a1;el compilador conoce el tipo de argumentoque deber
utilizar para construir la especializacin de cada mtodo de la
clase.
Por su parte, la declaracin de funcionesfriendgenricas, debe
hacerse en el cuerpo de la clase anfitriona, pero la definicin debe
hacerseantesdel cuerpo de dicha clase. A su vez, los prototipos
situados en el cuerpo de la clase, adems del especificadorfriend,
deben incluir un indicador del tipo de especializacin que se
pretende, mediante el indicadorsituado entre el nombre de la funcin
y la lista de argumentos (lo hemos denominadoinstanciacin explcita
especfica4.12.1). Es el caso esquematizado a continuacin relativo a
la clase anterior, en el que aadimos dos funciones amigas, que son
a su vez funciones genricas.template Array operator+ (const
Array& ar1, const Array& ar2) { // versin sobrecargada de
operator+() para concatenar rrays Array ax(len1 + len2); // Array
auxiliar para el resultado ... return ax;}template
std::ostream& operator