Un primer vistazo a las plantillas de C ++: programación genérica, plantillas de funciones y plantillas de clases.


Inserte la descripción de la imagen aquí

Uno, programación genérica

1.1 ¿Por qué utilizar la programación genérica?

Para escribir una función de intercambio general, podemos usar la sobrecarga de funciones. Los detalles específicos de la sobrecarga de funciones se pueden encontrar en el siguiente blog:
C ++ Elementary-Namespace, parámetros predeterminados y sobrecarga de funciones

void Swap(int& left, int& right)
{
    
    
	int temp = left;
	left = right;
	right = temp;
}
void Swap(double& left, double& right)
{
    
    
	double temp = left;
	left = right;
	right = temp;
}
void Swap(char& left, char& right)
{
    
    
	char temp = left;
	left = right;
	right = temp;
}

El uso de la sobrecarga de funciones puede lograr funciones de intercambio general, pero hay dos problemas

  • La sobrecarga de funciones es solo el tipo es diferente , la tasa de reutilización del código es baja, cuando aparece un nuevo tipo, se debe agregar la función correspondiente ;
  • La capacidad de mantenimiento del código es baja y un error hace que todas las sobrecargas salgan mal.
    Por lo tanto, la gente piensa en una forma de decirle al compilador un modelo, dejar que el compilador use el modelo para generar código de acuerdo con diferentes tipos , lo que conduce a una programación genérica .

2.2 ¿Qué es la programación genérica?

Escribir código genérico que no tenga nada que ver con tipos es un medio de reutilización de código. Las plantillas son la base de la programación genérica .

Inserte la descripción de la imagen aquí

Dos, plantilla de función

2.1 ¿Qué es una plantilla de función?

La 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 utiliza, y se genera una versión de tipo específico de la función de acuerdo con el tipo del parámetro actual .

2.2 ¿Cómo utilizar la plantilla de funciones?

<1> Formato de plantilla de función

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
Aquí hay una castaña:

//2.2 
template<typename T>
void Swap(T& left, T& right)
{
    
    
	T temp = left;
	left = right;
	right = temp;
}

Nota

typename se usa para definir palabras clave de parámetros de plantilla , y también puede usar class (recuerde: no puede usar struct en lugar de class)

2.3 Principio de la plantilla de funciones

La plantilla de función es un modelo, que en sí mismo no es una función , un compilador del molde para producir un uso particular de tipos particulares de funciones . Entonces, de hecho, la plantilla es para entregar las cosas repetitivas que deberíamos haber hecho al compilador.
Inserte la descripción de la imagen aquí
En la etapa de compilación del compilador, para el uso de las funciones de la plantilla, el compilador necesita deducir y generar los tipos correspondientes de funciones para la invocación basada en los tipos de argumentos pasados . Por ejemplo, cuando se usa una plantilla de función con el tipo doble, el compilador determina T como el tipo doble deduciendo el tipo del parámetro real, y luego genera un código que trata con el tipo doble, y lo mismo es cierto para el carácter. escribe.

<1> Creación de instancias de plantilla de función

Cuando se utiliza una plantilla de función con diferentes tipos de parámetros , 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. Creación de instancias implícita: deje que el compilador deduzca el tipo real del parámetro de plantilla en función del parámetro real
    Inserte la descripción de la imagen aquí
  2. Instanciación explícita: especifique el tipo real del parámetro de plantilla con <> después del nombre de la función.
    Inserte la descripción de la imagen aquí
    Si el tipo no coincide, el compilador intentará realizar una conversión de tipo implícita. Si la conversión falla, el compilador informará un error.

<2> El principio de coincidencia de los parámetros de la plantilla

  1. Una función que no es de plantilla puede existir al mismo tiempo que una plantilla de función con el mismo nombre, y la plantilla de función también se puede instanciar como la función que no es de plantilla .
// 专门处理int的加法函数
int Add(int left, int right)
{
    
    
	return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
    
    
	return left + right;
}

void Test()
{
    
    
	Add(1, 2); // 与非模板函数匹配,编译器不需要特化
	Add<int>(1, 2); // 调用编译器特化的Add版本
}

int main()
{
    
    
	Test();
	return 0;
}

Inserte la descripción de la imagen aquí
2. Para una función que no es de plantilla y una plantilla de función con el mismo nombre, si otras condiciones son las mismas, la función que no es de plantilla se llamará primero durante la transferencia y no se generará una instancia a partir de la plantilla. Si la plantilla puede producir una función con una mejor coincidencia, se seleccionará la plantilla .

// 专门处理int的加法函数
int Add(int left, int right)
{
    
    
	return left + right;
}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
    
    
	return left + right;
}
void Test()
{
    
    
	Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
	Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}

Inserte la descripción de la imagen aquí
3. Las funciones de plantilla no permiten la conversión automática de tipos, pero las funciones normales pueden realizar la conversión automática de tipos.

Tres, plantilla de clase

3.1 Formato de definición de la plantilla de clase

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

El uso de plantillas de clase es para resolver el problema de almacenar diferentes tipos de datos en la clase , por ejemplo:

// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{
    
    
public:
	Vector(size_t capacity = 10)
		: _pData(new T[capacity])
		, _size(0)
		, _capacity(capacity)
	{
    
    }
	// 析构函数
	~Vector()
	{
    
    
		if(_pData)
			delete[] _pData;
		_size = _capacity = 0;
	}
	void PushBack(const T& data)void PopBack()// ...
		size_t Size() {
    
     return _size; }
	T& operator[](size_t pos)
	{
    
    
		assert(pos < _size);
		return _pData[pos];
	}
private:
	T* _pData;
	size_t _size;
	size_t _capacity;
};

Cabe señalar aquí que si declaramos que la función en la clase se definirá fuera de la clase, entonces debemos agregar la lista de parámetros de la plantilla, como el destructor
Inserte la descripción de la imagen aquí

3.2 Creación de instancias de una plantilla de clase

¿Cómo usar la plantilla de clase anterior?

La instanciación de plantilla de clase es diferente de la instanciación de plantilla de función. La instanciación de plantilla de clase debe estar enNombre de la plantilla de clase seguido de <>,entoncesPonga el tipo instanciado en <>Es decir, el nombre de la plantilla de clase no es la clase real, pero el resultado de la instanciación es la clase real.

int main()
{
    
    
	Vector<int> s1;
	Vector<double> s2;
	Vector<char> s3;
	return 0;
}

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_40076022/article/details/114852730
Recomendado
Clasificación