Cómo usar plantillas C ++

Cómo usar plantillas C ++
En la programación básica de C ++, el tipo de datos, E.gramo., int o char, debe indicarse en una declaración o definición. Un valor como 4 o 22 o -5 es un int. Un valor como 'a' o 'b' o 'c' es un char. 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 C ++ tenga más de un tipo genérico. Con, por ejemplo, t para el int o char, puede soportar el tipo de flotador o puntero. 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. Por lo tanto, el mecanismo de plantilla también permite al programador utilizar 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 debería tener conocimiento de las entidades antes mencionadas para comprender los temas cubiertos en este artículo.

Tipos

Escalar

Los tipos escalares son nulo, bool, char, int, float y puntero.

Clases como tipos

Una clase en particular puede considerarse como un tipo y sus objetos como posibles valores.

Un tipo genérico representa un conjunto de tipos escalar. 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:

plantilla T pi = 3.14;

Antes de continuar, tenga en cuenta que este tipo de declaración no puede aparecer en la función Main () o cualquier alcance de bloque. La primera línea es la declaración de la plantilla de cabeza, 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 flotador o algún otro tipo, se puede hacer en la función C ++ Main () (o alguna otra función). Tal precisión se hará con la variable Pi, y no t.

La primera línea es la declaración de la plantilla. Esta declaración comienza con la palabra reservada, plantilla y luego los soportes de ángulo abierto y cerrado. Dentro de los soportes de ángulo, 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, nombre de tipo. Tales tipos genéricos en esa posición se llaman parámetros de plantilla.

La siguiente declaración se puede escribir en Main () o en cualquier otra función:

cout << pi << '\n';

Y la función mostraría 3.14. La expresión Pi decide el tipo exacto de t para la variable pi. La especialización decide el tipo de datos particular para el parámetro de plantilla. La instancia es el proceso interno de C ++ de crear el tipo particular, como Float, en este caso. No confunda entre instanciar un parámetro de plantilla e instanciar una clase. En el tema de la plantilla, muchos tipos de datos pueden tener un nombre de tipo genérico, mientras que muchas clases pueden tener un nombre de clase genérico. Sin embargo, el nombre de clase genérico para las clases se conoce simplemente como una clase, y no como un nombre de clase. Además, un valor es para un tipo de datos, como el int, como un objeto instanciado es para una clase, como la clase de cadena.

En la especialización, el tipo de datos elegido, como el flotador, se coloca en los soportes de ángulo después de la variable. Si hay más de un parámetro de plantilla en la declaración de cabeza 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 este y el argumento de la función para la llamada de función.

Tipo predeterminado

Si no se da ningún tipo en la especialización, se supone el tipo predeterminado. Entonces, de la siguiente expresión:

plantilla U pi = "amor";

Esta cámara se usará como tal con un tipo predeterminado:

cout << pi << '\n';

Por el cual el "amor" por el puntero constante a Char se usa como predeterminado desde la plantilla. Nota en la declaración de que U = const char*. Los soportes de ángulo estarán vacíos en la especialización (sin tipo dado); El tipo real se considera un puntero constante para Char, el tipo predeterminado. Si se necesitara algún otro tipo en la especialización, entonces el nombre del tipo se escribiría en los soportes de ángulo. Cuando se desea el tipo predeterminado en la especialización, repetir el tipo en los soportes de ángulo es opcional, i.mi., Los soportes de ángulo se pueden dejar vacío.

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:

plantilla estructura de edades

T John = 11;
T peter = 12;
T Mary = 13;
T Joy = 14;
;

Estas son edades de estudiantes en una calificación (clase). La primera línea es la declaración de plantilla. El cuerpo en aparatos ortopédicos es la definición real de la plantilla. Las edades se pueden emitir en la función Main () con lo siguiente:

Siglos grado 7;
cout << grade7.John << " << grade7.Mary << '\n';

La salida es: 11 13. La primera declaración aquí realiza la especialización. Tenga en cuenta cómo se ha hecho. También da un nombre para un objeto de la estructura: grado 7. La segunda declaración tiene expresiones de objetos de estructura ordinarios. Una estructura es como una clase. Aquí, las edades son como un nombre de clase, mientras que Grade7 es un objeto de la clase (struct).

Si algunas edades son enteros y otras son flotadores, entonces la estructura necesita dos parámetros genéricos, como sigue:

plantilla estructura de edades

T John = 11;
U Peter = 12.3;
T Mary = 13;
U Joy = 14.6;
;

Un código relevante para la función Main () es el siguiente:

Siglos grado 7;
cout << grade7.John << " << grade7.Peter << '\n';

La salida es: 11 12.3. En 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 la plantilla se puede separar de la definición, como sigue:

plantilla estructura de edades

T John;
U Peter;
T Mary;
Tu alegría;
;
Siglos grado 7 = 11, 12.3, 13, 14.6;

El primer segmento de código es puramente una declaración de una plantilla (no hay tareas). El segundo segmento de código, que es solo una declaración, es la definición del identificador, grado 7. El lado izquierdo es la declaración del identificador, grado 7. El lado derecho es la lista de inicializador, que asigna los valores correspondientes a los miembros de Struct. 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 de no datos incluyen int, puntero a objeto, puntero a la función y tipos de automóviles. 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 en particular, seguido de un identificador. El valor del identificador se da más adelante, en especialización, y no se puede cambiar nuevamente (como una constante, cuyo valor se da más adelante). El siguiente programa ilustra esto:

#incluir
usando el espacio de nombres STD;
plantilla estructura de edades

T John = n;
U Peter = 12.3;
T Mary = n;
U Joy = 14.6;
;
int main ()

Siglos grado 7;
cout << grade7.John << " << grade7.Joy << '\n';
regresar 0;

En la especialización, el primer tipo, int, en los soportes de ángulo está más para la formalidad, para asegurarse de que el número y el orden de los parámetros correspondan al número y el orden de los tipos (argumentos). El valor de n se ha dado en 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, existe la necesidad de dos tipos predeterminados. Esto se puede lograr utilizando la construcción de especialización parcial, que no emplea al operador de asignación. Entonces, la construcción de especialización parcial proporciona 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 (struct). El siguiente programa ilustra esto para un tipo genérico de dos tipos genéricos:

#incluir
usando el espacio de nombres STD;
// Clase de plantilla base
plantilla
estructura de edades

;
// especialización parcial
plantilla
estructura de edades

T1 John = 11;
Flotar Peter = 12.3;
T1 Mary = 13;
Joy de flotación = 14.6;
;
int main ()

Siglos grado 7;
cout << grade7.John << " << grade7.Joy << '\n';
regresar 0;

Identificar la declaración de clase base y su definición de clase parcial. La declaración de la plantilla de la clase base tiene todos los parámetros genéricos necesarios. La declaración de la plantilla de la clase de especialización parcial tiene solo el tipo genérico. Hay un conjunto adicional de soportes de ángulo utilizados en el esquema que se produce 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 defectuoso, en el orden escrito en la clase base. Tenga en cuenta que el tipo predeterminado todavía se le puede dar un tipo diferente en la función Main ().

El código relevante en la función main () puede ser el siguiente:

Siglos grado 7;
cout << 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 el nombre de tipo de palabras reservado o la clase. Esto es seguido por 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:

#incluir
usando el espacio de nombres STD;
plantilla estructura de edades

int John = 11;
Flotar Peter = 12.3;
int mary = 13;
Joy de flotación = 14.6;
;
int main ()

Siglos grado B;
cout << gradeB.John << " << gradeB.Mary << '\n';
Siglos Gradec;
cout << gradeC.Peter << " << gradeC.Joy << '\n';
Siglos calificado;
cout << gradeD.John << " << gradeD.Joy << '\n';
Edad gradea; // como predeterminado
cout << gradeA.John << " << gradeA.Joy << '\n';
regresar 0;

La salida es:

11 13
12.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érica y tres argumentos:

#incluir
usando el espacio de nombres STD;
plantilla vacío func (t no, u cha, const char *str)
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

int main ()
func (12, '$', "500");
regresar 0;

La salida es la siguiente:

Hay 12 libros por valor de $ 500 en la tienda.

Separación del prototipo

La definición de función se puede separar de su prototipo, como muestra el siguiente programa:

#incluir
usando el espacio de nombres STD;
plantilla nulo func (t no, u cha, const char *str);
plantilla vacío func (t no, u cha, const char *str)
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

int main ()
func (12, '$', "500");
regresar 0;

Nota: La declaración de plantilla de función no puede aparecer en la función main () o en cualquier otra función.

Sobrecarga

La sobrecarga de la misma función puede tener lugar con diferentes declaraciones de cabeza de plantilla. El siguiente programa ilustra esto:

#incluir
usando el espacio de nombres STD;
plantilla vacío func (t no, u cha, const char *str)
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

plantilla vacío func (t no, const char *str)
cout << "There are " << no << " books worth $" << str << " in the store." << '\n';

int main ()

func (12, '$', "500");
func (12, "500");
regresar 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:

#incluir
usando el espacio de nombres STD;
Clase THECLA

público:
int num;
Charch estático;
vacío func (char cha, const char *str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

Diversión nula estática (Char Ch)
if (ch == 'a')
cout << "Official static member function" << '\n';

;
int main ()

THECLA OBJ;
obj.num = 12;
obj.func ('$', "500");
regresar 0;

La salida es la siguiente:

Hay 12 libros por valor de $ 500 en la tienda.

El siguiente programa es el programa anterior con una declaración de cabeza de plantilla:

#incluir
usando el espacio de nombres STD;
plantilla Clase THECLA

público:
T num;
estático u ch;
vacío func (u cha, const char *str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

diversión nula estática (u ch)
if (ch == 'a')
cout << "Official static member function" << '\n';

;
int main ()

THECLA obj;
obj.num = 12;
obj.func ('$', "500");
regresar 0;

En lugar de la palabra typename en la lista de parámetros de plantilla, se puede usar la clase Word. 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:

plantilla clase thecla;
plantilla clase thecla
público:
T num;
estático u ch;
vacío func (u cha, const char *str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

diversión nula estática (u ch)
if (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:

#incluir
usando el espacio de nombres STD;
plantilla clase thecla
público:
T num;
estático u ch;
vacío func (u cha, const char *str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

diversión nula estática (u cha)
if (ch == 'a')
cout << "Official static member function" << cha << '\n';

;
plantilla U thecla:: CH = 'A';
int main ()

THECLA::divertido('.');
regresar 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. La salida es la siguiente:

Función oficial de miembros estáticos.

Compilación

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. Crear 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.