C++泛型编程——模板初阶

泛型编程

在生活中我们有各种模板,PPT模板,编辑模板,工厂里浇筑的模板等等,这些模板是可以重复利用,比如我们可以用一个PPT模板编辑不同的文字内容。而C++中的模板和这些也有异曲同工之妙的

在这里插入图片描述

比如我们要实现不同类型的交换函数,按照常规思路,每有一种类型就需要重载对应类型的交换函数

#include <iostream>
using namespace std;
//这里我们只写三种类型的
void Swap(char& a, char& b)
{
	char temp = a;
	a = b;
	b = temp;
}

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

int main()
{	
	char c1 = '0', c2 = '9';
	Swap(c1, c2);
	int i1 = 10, i2 = 20;
	Swap(i1, i2);
	double d1 = 2.0, d2 = 5.0;
	Swap(d1, d2);

	return 0;
}

可以发现三个Swap函数有多处冗余,且每增加一个新的类型就是增加一个对应的函数,代码复用性低,且对自定义类型会更加麻烦。 C++根据这样的问题提出了模板,这就是C++的泛型编程,编写与类型无关的通用代码,编译器根据不同的类型,生成不同类型的代码,是代码复用的一种手段。

模板是泛型编程的基础也是精华。模板分函数模板和类模板

在这里插入图片描述

函数模板

函数模板的概念

函数模板与类型无关,在使用时被参数化,是根据实参的类型产生函数的特定类型的模板

函数模板格式

template< class 形参名,class 形参名,......> 
返回类型 函数名(参数列表)  
 { 函数体 }
#include <iostream>
using namespace std;
//template是用来声明模板的
//class是定义模板的关键字,也可以使用typename,但typename与class不等价
template <class T>
void Swap(T& x1, T& x2)
{
	T tmp = x1;
	x1 = x2;
	x2 = tmp;
}
int main()
{	
	char c1 = '0', c2 = '9';
	Swap(c1, c2);
	int i1 = 10, i2 = 20;
	Swap(i1, i2);
	double d1 = 2.0, d2 = 5.0;
	Swap(d1, d2);

	return 0;
}

函数模板的原理

函数模板是一个蓝图,它本身并不是函数,编译器需要根据传入的实参类型实例化对应类型的函数,第一个swap函数的实参是char类型,编译器就会将T变为对应的char,后面的int,double也是如此,所以还是会生成我们之前写的三个重载函数,只是将我们需要重复做的事交给编译器完成了

通过汇编代码发现,每次都会call不同的函数,所以编译器还是会生成不同类型的函数,只不过不需要我们完成了
在这里插入图片描述在这里插入图片描述

函数模板实例化

函数模板实例化:根据实参推导出对应的类型,实例化出对应的函数
分为隐式实例化和显示实例化,上面我们实现的就是隐式实例化

隐式实例化

隐式实例化:编译器根据实参自动推导模板参数的实际类型

#include <iostream>
using namespace std;

template <class T>	//模板参数列表——参数类型
T Add(const T& x1, const T& x2)	//函数参数列表——参数对象
{
	return x1 + x2;
}

int main()
{
	int a = 5, b = 6;
	double c = 11.1, d = 12.2;
	cout << Add(a, b) << endl;//根据实参推出T是int
	cout << Add(c, d) << endl;//根据实参推出T是double
	
	//这里编译器就会报错,因为a与c的类型不一致,编译器无法确定T是int还是double
	cout << Add(a, c) << endl;

	return 0;
}

在这里插入图片描述

想要编译通过有三种方式:

  • 强制类型转换
	cout << Add((double)a, c) << endl;
  • 设置两个T
template <class T1, class T2>	
T1 Add(const T1& x1, const T2& x2)//返回类型就只能设置一个了
{
	return x1 + x2;
}
  • 显示实例化

显示实例化

在函数名后的<>中指定模板参数的实际类型

#include <iostream>
using namespace std;

template <class T>	//模板参数列表——参数类型
T Add(const T& x1, const T& x2)	//函数参数列表——参数对象
{
	return x1 + x2;
}

int main()
{
	int a = 5, b = 6;
	double c = 11.1, d = 12.2;
	cout << Add(a, b) << endl;//根据实参推出T是int
	cout << Add(c, d) << endl;//根据实参推出T是double
	
	cout << Add<double>(a, c) << endl;//直接将T设为double

	return 0;
}

模板参数匹配原则

如果非模板函数与同名的模板函数同时存在,且调用时条件都相同,那么调用时会优先调用非模板函数
在这里插入图片描述如果模板能产生一个更好的匹配函数,那么调用时会优先选择模板
在这里插入图片描述

类模板

需要注意的是,类模板是一个模板,模板类是由类模板实例化的具体类

类模板的定义

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

类模板实例化

这里我们简单实现一个栈的类模板

#include <iostream>
using namespace std;
//对普通的类而言,类名就是类型
//而对类模板而言,stack是类名,stack<T>才是类型
template<class T>
class stack
{
public:
	stack(int capacity = 4)
		:_capacity(capacity)
	{
		T* _p = new int[capacity];
		_top = 0;
		_capacity = capacity;
	}
	~stack()
	{
		delete[] _p;
		_top = _capacity = 0;
	}
private:
	T* _p;
	int _top;
	int _capacity;
};
//类模板实例化与函数模板实例化不同,需要在类模板名字后跟<>指定类型
int main()
{	
	//类模板只支持显示实例化
	stack<int> s1;//定义一个int类型的栈
	stack<float> s2;//定义一个float类型的栈
	stack<double> s3;//定义一个double类型的栈

	return 0;
}

类模板使用注意事项

当我们在类模板中只声明了函数,而在类外面定义时,就需要注意了,在类模板外面定义的模板函数一定要加template

template<class T>
class stack
{
public:
	stack(int capacity = 4)
		:_capacity(capacity)
	{
		T* _p = new int[capacity];
		_top = 0;
		_capacity = capacity;
	}
	~stack()
	{
		delete[] _p;
		_top = _capacity = 0;
	}
	//在类模板中声明push函数
	void push(const T& x);

private:
	T* _p;
	int _top;
	int _capacity;
};
//错误写法
//void stack::push(const T& x)
//{

//}
//类模板中函数放在类外进行定义时,需要加模板参数列表
//如果没有template,编译器就会认为这仅仅是全局的函数,无法确定它的类型
//template是用来声明push函数是一个函数模板,用来消除除歧义的
template<class T>
//栈的类型为stack<T>,而不是stack
void stack<T>::push(const T& x)
{
	
}

今天对泛型编程的介绍到这里就结束了,希望我的文章对你有所帮助,欢迎👍点赞 ,📝评论,🌟关注,⭐️收藏

在这里插入图片描述

  • 48
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 41
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 41
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

寄一片海给你

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

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

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

打赏作者

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

抵扣说明:

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

余额充值