C++——Plantilla elemental


Prefacio:

En este capítulo, aprenderemos plantillas y contactaremos formalmente con la programación genérica. C++En comparación con Clos lenguajes, hay tantas interfaces y tipos ricos, todos los cuales se originan en la programación genérica. STLEl contenido de este capítulo es el conocimiento inicial de la plantilla, que sentará una base sólida para el próximo estudio.

1. Programación genérica

¿ Cómo implementar una función de intercambio general ( swap)? Ya hemos aprendido el uso de la sobrecarga de funciones, y la sobrecarga de funciones es muy útil en este escenario:

void Swap(int& a, int& b)
{
    
    
	auto tmp = a;
	a = b;
	b = tmp;
}

void Swap(double& a, double& b)
{
    
    
	auto tmp = a;
	a = b;
	b = tmp;
}

void Swap(char& a, char& b)
{
    
    
	auto tmp = a;
	a = b;
	b = tmp;
}
//...

Aunque es posible utilizar la sobrecarga de funciones , existen varias desventajas:

  1. Las funciones sobrecargadas son solo de diferentes tipos, y la tasa de reutilización de código es relativamente baja. Siempre que aparezca un nuevo tipo, el usuario debe agregar la función correspondiente
  2. La mantenibilidad del código es relativamente baja, un error puede causar que todas las sobrecargas sean un error

¿Puede decirle al compilador un modelo y dejar que el compilador use el modelo para generar código de acuerdo con diferentes tipos?

  • Esta es la plantilla de la que vamos a hablar hoy : la plantilla es la base de la programación genérica . Las plantillas se aplican no sólo a las funciones , sino también a las clases .

2. Plantilla de función

1. El concepto de plantilla de funciones

Una plantilla de función representa una familia de funciones . La plantilla de función no tiene nada que ver con el tipo . Se parametriza cuando se usa, y se genera una versión de tipo específica de la función de acuerdo con el tipo del parámetro real.

2. El formato de la plantilla de función

template<typename T1, typename T2,......,typename TN>
返回值类型 函数名(参数列表)
{
    
    
	//...函数体
}

Ejemplo:

template<typename T>
void Swap(T& a,T& b)
{
    
    
	auto tmp = a;
	a = b;
	b = tmp;
}
template<class N>
void Swap(N& a, N& b)
{
    
    
	auto tmp = a;
	a = b;
	b = tmp;
}

Aviso:

  1. typenameEl siguiente contenido no tiene que ser T, se puede especificar libremente;
  2. typenameSe usa para definir palabras clave de parámetros de plantilla y también se puede usar class(recuerde: no se puede usar structen su lugar class)

3. El principio de la plantilla de funciones.

Una plantilla de función es un proceso de descripción, un modelo, una plantilla , no una función real. El compilador genera funciones de tipo concreto de forma específica en base a la plantilla . Entonces, de hecho, la plantilla es para entregar las cosas repetitivas que debemos hacer al compilador (piense en el principio de impresión).

inserte la descripción de la imagen aquí

En la etapa de compilación del compilador, el compilador necesita deducir y generar una función del tipo correspondiente según el tipo del parámetro real entrante para la llamada.

Por ejemplo: al usar una plantilla de función con el tipo e, el compilador determinará el tipo doubldeduciendo el tipo del parámetro real y luego generará un código que maneja específicamente el tipo, y lo mismo se aplica al tipo de carácter.Tdoubledouble

4. Creación de instancias de plantillas de funciones

Cuando una plantilla de función se utiliza con parámetros de diferentes tipos , se denomina instanciación de la plantilla de función . La instanciación de parámetros de plantilla se divide en: instanciación implícita y instanciación explícita .

(1) Instanciación implícita

Deje que el compilador deduzca el tipo real del parámetro de plantilla en función del parámetro real.

Ejemplo:

template<class T>
T Add(T a, T b)
{
    
    
	return  a + b;
}
void Test()
{
    
    
	int a = 10;
	int b = 100;
	cout << Add(a, b) << endl;
}

inserte la descripción de la imagen aquí

(2) Instanciación explícita

Especifique el tipo real del parámetro de plantilla<> después del nombre de la función .

Ejemplo de error:

template<class T>
T Add(T a, T b)
{
    
    
	return  a + b;
}

void Test()
{
    
    
	int a = 10;
	double d = 3.14;

	cout << Add(a, d) << endl;
}

resultado de la operación:

inserte la descripción de la imagen aquí

razón incorrecta:

  • Porque durante la compilación, cuando el compilador ve la creación de instancias, necesita deducir su tipo de parámetro del parámetro real , y el parámetro real ase deducirá en el tipo, pero solo hay una lista de parámetros de plantilla, y el compilador no puede determinar si debe determinarse como o el tipo e informa un error.TintdTdoubleTTintdouble

forma correcta

①Instanciación explícita : le está diciendo al compilador: no necesita deducirlo, ya he especificado este tipo.

template<class T>
T Add(T a, T b)
{
    
    
	return  a + b;
}

void Test()
{
    
    
	int a = 10;
	double d = 3.14;
	cout << Add<int>(a, d) << endl;
}

inserte la descripción de la imagen aquí

② Uso de múltiples parámetros de plantilla :

template<class T,class Y>
Y Add(T a, Y b)
{
    
    
	return  a + b;
}

void Test()
{
    
    
	int a = 10;
	double d = 3.14;
	cout << Add(a, d) << endl;
}

inserte la descripción de la imagen aquí

Aviso:

  • ¡En el siguiente caso, la función llamada dos veces swapno es la misma función!
template<class N>
void Swap(N& a, N& b)
{
    
    
	auto tmp = a;
	a = b;
	b = tmp;
}
void Test()
{
    
    
	int a = 10;
	int b = 100;
	Swap(a,b);

	char c1 = 'a';
	char c2 = 'b';
	Swap(c1, c2);
}

El código ensamblador se muestra en la siguiente figura, obviamente la función llamada dos veces no es una función (un tipo es Swap< int >, uno es Swap< char >). De hecho, aunque no podemos ver el código de estas dos funciones, en realidad generan:

inserte la descripción de la imagen aquí

5. Principio de coincidencia de los parámetros de la plantilla

①Una función sin plantilla puede coexistir con una plantilla de función con el mismo nombre , y la plantilla de función también se puede instanciar como esta función sin plantilla .

template<class T>
T Add(T a, T b)
{
    
    
	return  a + b;
}

int Add(int a, int b)
{
    
    
	return a + b;
}

void Test()
{
    
    
	int a = 10;
	int b = 100;
	cout << Add<int>(a, b) << endl;
}

②Para una función sin plantilla y una función con plantilla con el mismo nombre , si las otras condiciones son las mismas, se llamará primero a la función sin plantilla y no se generará una instancia a partir de la plantilla cuando se movilice. Si la plantilla puede producir una función con una mejor coincidencia , entonces se elegirá la plantilla .

template<class T,class Y>
Y Add(T a, Y b)
{
    
    
	cout << "模板" << endl;
	return  a + b;
}
int Add(int a, int b)
{
    
    
	cout << "非模板" << endl;
	return a + b;
}
void Test()
{
    
    
	int a = 10;
	int b = 100;
	double d = 3.14;
	cout << Add(a, b) << endl;//使用非模板函数
	cout << Add(a, d) << endl;//使用模板
}

inserte la descripción de la imagen aquí

③Las funciones de plantilla no permiten la conversión de tipo automática , pero las funciones ordinarias pueden realizar la conversión de tipo automática

3. Plantilla de clase

1. Formato de definición de plantilla de clase

template<class T1, class T2, ..., class Tn>
class 类模板名
{
    
    
	// 类内成员定义
};

Ejemplo:

template<class T>
class Stack
{
    
    
public:
	//...
private:
	T* _a;
	size_t _size;
	size_t _capacity;
};

2. Creación de instancias de plantillas de clase

La creación de instancias de una plantilla de clase es diferente de la creación de instancias de una plantilla de función. La creación de instancias de una plantilla de clase debe ir seguida del nombre de la plantilla de clase, <>y luego <>se puede colocar el tipo instanciado en ella. El nombre de la plantilla de clase no es una clase real, pero el resultado de la creación de instancias es la clase real .

// Stack类名,Stack<int>是类型
Stack<int> s1;
Stack<double> s2

Este es el final de este artículo, el texto del código no es fácil, ¡por favor ayúdenme mucho!

Supongo que te gusta

Origin blog.csdn.net/weixin_67401157/article/details/130748474
Recomendado
Clasificación