【C++】模板初阶

✨✨欢迎大家来到Celia的博客✨✨

🎉🎉创作不易,请点赞关注,多多支持哦🎉🎉

所属专栏:C++

个人主页Celia's blog~

一、泛型编程

  在C语言中,我们想要交换两个变量的值,可以写一个Swap函数,如果我们想要交换不同类型的变量,就需要额外再写一个参数列表不同的Swap函数。在C++中,提供了模板这一方式来更加便利的解决这些问题。泛型编程就是编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

二、函数模板

2.1 定义格式

  定义模板需要用到关键字template,后面跟上<>,在尖括号中包含需要替代的数据类型种类,格式为 class T 或 typename T(不能使用struct  T)。T,为指代的类型名,仅仅具有指代作用,可以是任意的名字。如果有多个类型种类,用逗号隔开。

template<class T>
void Swap(T& x1, T& x2)
{
	T tmp = x1;
	x1 = x2;
	x2 = tmp;
}

编译器会根据传入的形参来自动匹配T具体的数据类型。编译器会根据T的类型来根据模板自动生成一个函数。每个模板函数都需要在函数的定义前加上template<class T , ...>。

2.2 使用格式

//函数模板
template<class T>
void Swap(T& x1, T& x2)
{
	T tmp = x1;
	x1 = x2;
	x2 = tmp;
}

int main()
{
	int x1 = 2, x2 = 4;
	Swap(x1, x2);
	cout << x1 << x2;

	return 0;
}

2.3 模板实例化

  用不同类型的参数使用函数模板时,叫做函数模板的实例化。实例化又分为隐式实例化和显式实例化。

2.3.1 隐式实例化

  隐式实例化就是让编译器自动识别模板参数的实际类型,例如:

int main()
{
	int x1 = 2, x2 = 4;
	Swap(x1, x2);
	cout << x1 << x2;

	return 0;
}

编译器会根据传入的x1、x2来自动识别模板的实际类型。

2.3.2 显式实例化

   显式实例化就是在函数名的后面加上<类型名>显式指定模板参数的实际类型。例如:

int main()
{
	int x1 = 2, x2 = 4;
	Swap<int>(x1, x2);
	cout << x1 << x2;

	return 0;
}

如果传入参数的类型与指定的类型不匹配,编译器会尝试隐式类型转换,如果转换不成功则会报错。 

2.4 模板函数的匹配规则

  • 模板函数可以和一个非模板的同名函数同时存在。在调用这个函数时,如果不显式实例化,编译器会优先调用非模板函数。
//函数模板
template<class T>
void Swap(T& x1, T& x2)
{
	T tmp = x1;
	x1 = x2;
	x2 = tmp;
}

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

int main()
{
	int x1 = 2, x2 = 4;
	Swap(x1, x2);//调用非模板函数
	Swap<int>(x1, x2);//调用模板函数

	cout << x1 << x2;

	return 0;
}
  • 如果函数模板可以生成更加匹配的模板函数,编译器会优先调用模板函数。

//函数模板
template<class T1, class T2>
T1 Add(T1 x1, T2 x2)
{
	return x1 + x2;
}
//通用函数
int Add(int a, int b)
{
	return a + b;
}

int main()
{
	int x1 = Add(1, 2);//和通用函数完全匹配,调用通用函数
	double x2 = Add(1.0, 2);//函数模板能生成更合适的函数,调用模板函数
	return 0;
}

三、类模板

3.1 类模板的定义格式

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

示例:

//类模板(栈)
template<class T>
class Stack
{
public:
	Stack(int n = 4)
		:_capacity(n),
		_size(0),
		_a(new T[n])
	{}
	~Stack()
	{
		delete[] _a;
	}
	void Push(T data);
	
	void Pop()
	{
		_size--;
	}

private:
	int _capacity;
	int _size;
	T* _a;
};

template<class T>
void Stack<T>::Push(T data)
{
	if (_size == _capacity)
	{
		T* tmp = new T[_capacity << 1];
		memcpy(tmp, _a, sizeof(T) * _capacity);

		delete[] _a;
		_a = tmp;

		tmp = nullptr;
		_capacity <<= 1;
	}
	_a[_size++] = data;
}

int main()
{
	Stack<int> s;
	s.Push(1);
	s.Push(2);
	s.Push(3);
	s.Push(4);
	s.Push(5);
	s.Push(6);

	return 0;
}

 3.2 类模板的注意事项

  • 模板类中的成员函数在类外定义时,函数定义前需要加上template<class T>,函数名后需要加上<类型>。
  • 类模板的实例化需要显式指定具体类型。实例化后的才是类型名。
    // Stack是类名,Stack<int>才是类型
    Stack<int> st1; // int
    Stack<char> st2; // char
  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Celia~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值