Introducción
En la programación básica de C ++, el tipo de datos, e.gramo., int o char, debe indicarse en una declaración o una definición. Un valor como 4 o 22 o -5 es un int. Un valor como 'A' o 'b' o 'c' es un carácter. El mecanismo de plantilla permite al programador usar un tipo genérico para un conjunto de tipos reales. Por ejemplo, el programador puede decidir usar el identificador T para int o char. Es posible que un algoritmo de C ++ tenga más de un tipo genérico. Con, digamos, T para int o char, U puede representar el tipo float o pointer. Una clase, como la clase de cadena o vector, es como un tipo de datos, y los objetos instanciados son como valores del tipo de datos, que es la clase especificada. Entonces, el mecanismo de plantilla también permite al programador usar un identificador de tipo genérico para un conjunto de clases.
Una plantilla de C ++ crea un algoritmo independiente del tipo de datos empleados. Entonces, el mismo algoritmo, con muchas ocurrencias del mismo tipo, puede usar diferentes tipos en diferentes ejecuciones. Las entidades de variable, función, estructura y clase pueden tener plantillas. Este artículo explica cómo declarar plantillas, cómo definir plantillas y cómo aplicarlas en C++. Ya debe tener conocimiento de las entidades antes mencionadas para comprender los temas cubiertos en este artículo.
Tipos
Escalar
Los tipos escalares son void, bool, char, int, float y pointer.
Clases como tipos
Una clase particular se puede considerar como un tipo y sus objetos como posibles valores.
Un tipo genérico representa un conjunto de tipos escalares. La lista de tipos escalares es extensa. El tipo int, por ejemplo, tiene otros tipos relacionados, como short int, long int, etc. Un tipo genérico también puede representar un conjunto de clases.
Variable
Un ejemplo de una declaración y definición de plantilla es el siguiente:
plantillaT pi = 3.14;
Antes de continuar, tenga en cuenta que este tipo de declaración no puede aparecer en la función main () ni en ningún alcance de bloque. La primera línea es la declaración de encabezado de plantilla, con el nombre de tipo genérico elegido por el programador, T. La siguiente línea es la definición del identificador, pi, que es del tipo genérico, T. La precisión, de si la T es un int o un flotante o algún otro tipo, se puede hacer en la función main () de C ++ (o alguna otra función). Tal precisión se hará con la variable pi, y no con T.
La primera línea es la declaración de encabezado de plantilla. Esta declaración comienza con la palabra reservada, la plantilla y luego los corchetes angulares abiertos y cerrados. Dentro de los corchetes angulares, hay al menos un identificador de tipo genérico, como T, arriba. Puede haber más de un identificador de tipo genérico, cada uno precedido por la palabra reservada, typename. Estos tipos genéricos en esa posición se denominan parámetros de plantilla.
La siguiente declaración se puede escribir en main () o en cualquier otra función:
cout << piY la función mostraría 3.14. La expresión pi
En la especialización, el tipo de datos elegido, como float, se coloca entre paréntesis angulares después de la variable. Si hay más de un parámetro de plantilla en la declaración de encabezado de plantilla, habrá un número correspondiente de tipos de datos en el mismo orden en la expresión de especialización.
En la especialización, un tipo se conoce como argumento de plantilla. No confunda entre esto y el argumento de la función para la llamada a la función.
Tipo predeterminado
Si no se proporciona ningún tipo en la especialización, se asume el tipo predeterminado. Entonces, de la siguiente expresión:
plantillaU pi = "amor";
la pantalla de:
cout << pi<> << '\n';
es "amor" para el puntero constante a char. Tenga en cuenta en la declaración que U = const char *. Los corchetes angulares estarán vacíos en la especialización (no se proporciona ningún tipo); el tipo real se considera un puntero constante a char, el tipo predeterminado. Si se necesitara algún otro tipo en la especialización, entonces el nombre del tipo se escribiría entre corchetes angulares. Cuando se desea el tipo predeterminado en la especialización, repetir el tipo en los corchetes angulares es opcional, i.mi., los corchetes angulares se pueden dejar vacíos.
Nota: el tipo predeterminado aún se puede cambiar en la especialización al tener un tipo diferente.
estructura
El siguiente ejemplo muestra cómo se puede usar un parámetro de plantilla con una estructura:
plantillaT John = 11;
T Peter = 12;
T María = 13;
T Joy = 14;
;
Estas son las edades de los estudiantes en un grado (clase). La primera línea es la declaración de la plantilla. El cuerpo entre llaves es la definición real de la plantilla. Las edades se pueden generar en la función main () con lo siguiente:
Sigloscout << grade7.John << " << grade7.Mary << '\n';
La salida es: 11 13. La primera declaración aquí realiza la especialización. Note como se ha hecho. También le da un nombre a un objeto de la estructura: grade7. La segunda declaración tiene expresiones de objeto de estructura ordinarias. Una estructura es como una clase. Aquí, Ages es como un nombre de clase, mientras que grade7 es un objeto de la clase (estructura).
Si algunas edades son números enteros y otras son flotantes, entonces la estructura necesita dos parámetros genéricos, como sigue:
plantillaT John = 11;
U Peter = 12.3;
T María = 13;
U Alegría = 14.6;
;
Un código relevante para la función main () es el siguiente:
Sigloscout << grade7.John << " << grade7.Peter << '\n';
La salida es: 11 12.3. En la especialización, el orden de los tipos (argumentos) debe corresponder al orden de los tipos genéricos en la declaración.
La declaración de plantilla se puede separar de la definición de la siguiente manera:
plantillaT John;
U Peter;
T Mary;
U Joy;
;
Siglos
El primer segmento de código es puramente una declaración de una plantilla (no hay asignaciones). El segundo segmento de código, que es solo una declaración, es la definición del identificador, grado7. El lado izquierdo es la declaración del identificador, grado 7. El lado derecho es la lista de inicializadores, que asigna los valores correspondientes a los miembros de la estructura. El segundo segmento (declaración) se puede escribir en la función main (), mientras que el primer segmento permanece fuera de la función main ().
No tipo
Ejemplos de tipos que no son de datos incluyen int, pointer to object, pointer to function y auto types. Hay otros no tipos, que este artículo no aborda. Un no tipo es como un tipo incompleto, cuyo valor se da más adelante y no se puede cambiar. Como parámetro, comienza con un no tipo particular, seguido de un identificador. El valor del identificador se da más tarde, en la especialización, y no se puede volver a cambiar (como una constante, cuyo valor se da más adelante). El siguiente programa ilustra esto:
#incluirusando el espacio de nombres std;
plantilla
T John = N;
U Peter = 12.3;
T María = N;
U Alegría = 14.6;
;
int main ()
Siglos
cout << grade7.John << " << grade7.Joy << '\n';
return 0;
En la especialización, el primer tipo, int, en los corchetes angulares es más por formalidad, para asegurarse de que el número y el orden de los parámetros se correspondan con el número y el orden de los tipos (argumentos). El valor de N se ha dado en la especialización. La salida es: 11 14.6.
Especialización parcial
Supongamos que una plantilla tiene cuatro tipos genéricos y que, entre los cuatro tipos, se necesitan dos tipos predeterminados. Esto se puede lograr utilizando la construcción de especialización parcial, que no emplea el operador de asignación. Entonces, la construcción de especialización parcial da valores predeterminados a un subconjunto de tipos genéricos. Sin embargo, en el esquema de especialización parcial, se necesitan una clase base (estructura) y una clase de especialización parcial (estructura). El siguiente programa ilustra esto para un tipo genérico de entre dos tipos genéricos:
#incluirusando el espacio de nombres std;
// clase de plantilla base
plantilla
Edades de estructura
;
// especialización parcial
plantilla
Edades de estructura
T1 John = 11;
Peter flotante = 12.3;
T1 María = 13;
flotar Alegría = 14.6;
;
int main ()
Siglos
cout << grade7.John << " << grade7.Joy << '\n';
return 0;
Identificar la declaración de clase base y su definición de clase parcial. La declaración de encabezado de plantilla de la clase base tiene todos los parámetros genéricos necesarios. La declaración de encabezado de plantilla de la clase de especialización parcial solo tiene el tipo genérico. Hay un conjunto adicional de corchetes angulares usados en el esquema que viene justo después del nombre de la clase en la definición de especialización parcial. Es lo que realmente hace la especialización parcial. Tiene el tipo predeterminado y el tipo no predeterminado, en el orden escrito en la clase base. Tenga en cuenta que el tipo predeterminado aún puede recibir un tipo diferente en la función main ().
El código relevante en la función main () puede ser el siguiente:
Sigloscout << grade7.John << " << grade7.Joy << '\n';
La salida es: 11 14.6.
Paquete de parámetros de plantilla
Un paquete de parámetros es un parámetro de plantilla que acepta cero o más tipos genéricos de plantilla para los tipos de datos correspondientes. El parámetro del paquete de parámetros comienza con la palabra reservada typename o class. A esto le siguen tres puntos y luego el identificador del paquete. El siguiente programa ilustra cómo se puede usar un paquete de parámetros de plantilla con una estructura:
#incluirusando el espacio de nombres std;
plantilla
int John = 11;
Peter flotante = 12.3;
int Mary = 13;
flotar Alegría = 14.6;
;
int main ()
Siglos
cout << gradeB.John << " << gradeB.Mary << '\n';
Siglos
cout << gradeC.Peter << " << gradeC.Joy << '\n';
Siglos
cout << gradeD.John << " << gradeD.Joy << '\n';
Edades <> gradoA; // como por defecto
cout << gradeA.John << " << gradeA.Joy << '\n';
return 0;
La salida es:
11 1312.3 14.6
11 14.6
11 14.6
Plantillas de funciones
Las características de la plantilla mencionadas anteriormente se aplican de manera similar a las plantillas de funciones. El siguiente programa muestra una función con dos parámetros de plantilla genéricos y tres argumentos:
#incluirusando el espacio de nombres std;
plantilla
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';
int main ()
func (12, '$', "500");
return 0;
El resultado es el siguiente:
Hay 12 libros por valor de $ 500 en la tienda.
Separación del prototipo
La definición de la función se puede separar de su prototipo, como muestra el siguiente programa:
#incluirusando el espacio de nombres std;
plantilla
plantilla
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';
int main ()
func (12, '$', "500");
return 0;
Nota: La declaración de la plantilla de función no puede aparecer en la función main () ni en ninguna otra función.
Sobrecarga
La sobrecarga de la misma función puede tener lugar con diferentes declaraciones de encabezado de plantilla. El siguiente programa ilustra esto:
#incluirusando el espacio de nombres std;
plantilla
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';
plantilla
cout << "There are " << no << " books worth $" << str << " in the store." << '\n';
int main ()
func (12, '$', "500");
func (12, "500");
return 0;
La salida es:
Hay 12 libros por valor de $ 500 en la tienda.
Hay 12 libros por valor de $ 500 en la tienda.
Plantillas de clase
Las características de las plantillas mencionadas anteriormente se aplican de manera similar a las plantillas de clase. El siguiente programa es la declaración, definición y uso de una clase simple:
#incluirusando el espacio de nombres std;
clase TheCla
público:
int num;
static char ch;
void func (char cha, const char * str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
diversión del vacío estático (char ch)
si (ch == 'a')
cout << "Official static member function" << '\n';
;
int main ()
TheCla obj;
obj.num = 12;
obj.func ('$', "500");
return 0;
El resultado es el siguiente:
Hay 12 libros por valor de $ 500 en la tienda.
El siguiente programa es el programa anterior con una declaración de encabezado de plantilla:
#incluirusando el espacio de nombres std;
plantilla
público:
T num;
estático U ch;
void func (U cha, const char * str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
diversión del vacío estático (U ch)
si (ch == 'a')
cout << "Official static member function" << '\n';
;
int main ()
TheCla
obj.num = 12;
obj.func ('$', "500");
return 0;
En lugar de la palabra typename en la lista de parámetros de la plantilla, se puede usar la palabra class. Tenga en cuenta la especialización en la declaración del objeto. La salida sigue siendo la misma:
Hay 12 libros por valor de $ 500 en la tienda.
Declaración de separación
La declaración de plantilla de clase se puede separar del código de clase, de la siguiente manera:
plantillaplantilla
público:
T num;
estático U ch;
void func (U cha, const char * str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
diversión del vacío estático (U ch)
si (ch == 'a')
cout << "Official static member function" << '\n';
;
Tratar con miembros estáticos
El siguiente programa muestra cómo acceder a un miembro de datos estáticos y una función de miembro estático:
#incluirusando el espacio de nombres std;
plantilla
público:
T num;
estático U ch;
void func (U cha, const char * str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
diversión del vacío estático (U cha)
si (ch == 'a')
cout << "Official static member function" << cha << '\n';
;
plantilla
int main ()
TheCla
return 0;
Asignar un valor a un miembro de datos estáticos es una declaración y no puede estar en main (). Tenga en cuenta el uso y las posiciones de los tipos genéricos y el tipo genérico de datos en la declaración de asignación. Además, tenga en cuenta que la función de miembro de datos estáticos se ha llamado en main (), con los tipos de datos de plantilla reales. El resultado es el siguiente:
Función de miembro estático oficial.
Compilando
La declaración (encabezado) y la definición de una plantilla deben estar en un archivo. Es decir, deben estar en la misma unidad de traducción.
Conclusión
Las plantillas de C ++ hacen que un algoritmo sea independiente del tipo de datos empleados. Las entidades de variable, función, estructura y clase pueden tener plantillas, que implican declaración y definición. La creación de una plantilla también implica especialización, que es cuando un tipo genérico toma un tipo real. La declaración y la definición de una plantilla deben estar en una unidad de traducción.