c++函数模板,类模板以使用


前言:泛型编程,大家应该都听过,c++是支持泛型编程的,C语言不支持,泛型编程的实现离不开模板。模板由函数模板,类模板组成。
在这里插入图片描述


1.函数模板

函数模板代表了一个函数家族,它可以被实例化成具体的函数,但必须是使用时被参数化,根据参数而实例成具体的函数。
比如交换函数,我可能要交换的数据是整型,浮点型,字符型等等,要是C语言我们就需要写对应的版本,但是c++支持泛型编程,我们来用一个函数模板就能在使用时实例化成对应的交换函数版本。

(1) 函数模板的格式

template<typename T1, typename T2,…,typename Tn>
返回值类型 函数名(参数列表)
{}

(2) 交换函数的函数模板
template<typename T>
void Swap( T& x, T& y)
{
 T temp = x;
 x = y;
 y = temp;
}
(3) 通过调试 交换函数 ,理解函数模板原理
#include<iostream>
using namespace std;
template<typename T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}
int main()
{
	//整型
	int a = 1; int b = 2;
	Swap(a, b);
	//浮点型
	float x = 1.1; float y = 2.2;
	Swap(x, y);
	//字符型
	char i = 'a'; char u = 'b';
	Swap(i, u);
	return 0;
}

首先,Swap(a,b),整型的交换。
在这里插入图片描述
进入Swap函数后,可以看到left,right的类型是整型,进行整型交换,
在这里插入图片描述
再来看Swap(x,y),交换浮点型数据,
在这里插入图片描述
最后交换字符型数据,
在这里插入图片描述
分析:可以看到,在进行传参时,根据传参的不同,函数也会实例化成相应的函数,具体可看上面调试中left,right的变化,传int型时,left,right为int;传float时,left和right为float;传char时,left和right为char。
具体关系如下图:
在这里插入图片描述
也就是说,函数模板可以根据传参来自动推演成相应的函数。
当然,如果不想让函数模板去推演,也可以自己显示的实例化,

Swap<类型>(a,b);
(4) 模板参数的匹配机制

上文中,Swap函数只能匹配同类型的数据交换,如果交换int和char就会出错,
如下:

//混合型交换
int m = 10; char w='Q';
Swap(m, w);

在这里插入图片描述
原因很简单,函数模板中只有一个参数T,这表明传来的参数必须是相同的类型,否则就会实例化失败。
解决方案:模板中再给一个参数T1,两个不同参数,所以可以有俩种类型。

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

那么可以想到,如果传的参数是三种类型,那么必须有三个模板参数去对应。
还有一种情况,假如Swap函数有专门处理整型类型数据转换的,会不会去调用模板去实例化呢?还是说根本就不会实例化,直接去调用专门的函数呢?
我们可以实验一下:

void Swap(int& x, int& y)
{
	int temp = x;
	x = y;
	y = temp;
}

调试来看一看:
在这里插入图片描述
小黄标指在专门的函数上,说明它去调用专门的对应函数了。
结论:
对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板(这种情况说明那个函数还不够专门)。


2. 类模板

类模板就是,c++中的类中成员需要支持泛型,也就是类的成员可能根据需求类型会发生改变。

(1) 类模板的格式
template<class T1, class T2, ..., class Tn>
class 类模板名
{
 // 类内成员定义
}; 

举一个例子:类模板A可以创建包含不同类型的数组,数组包含_a个元素。

template<class T>
class A
{
public:
	A(int a = 1)
	{
		_a = a;
		ptr = new T[_a];
	}
	~A()
	{
		delete[] ptr;
		ptr = nullptr;
		_a = 0;
	}
private:
	int _a;
	T* ptr;
};

可以看到,这个类模板A就实现了这样的功能,可以根据需求,包含不同类型的数组,具体类型不是靠传参,不能像函数模板那样去推演,只能显示的实例化类模板。

(2) 类模板的使用
#include<iostream>
using namespace std;
template<class T>
class A
{
public:
	A(int a = 1)
	{
		_a = a;
		ptr = new T[_a];
	}
	~A()
	{
		delete[] ptr;
		ptr = nullptr;
		_a = 0;
	}
private:
	int _a;
	T* ptr;
};
int main()
{
	A<int> m(3);
	A<double>w(4);
	A<char>E(5);
	return 0;
}

模板类和普通的类不同:

  • 普通的类:类名+对象名就可以了,类名就是类。
  • 模板类:类名<类型> +对象名才行,并且类名<类型>才是类。

通过调试带大家看一看。
在这里插入图片描述
可以清楚看到,int*,double*,char*,根据需求开辟了不同类型的数组。
还需要强调一点:类模板中函数放在类外进行定义时,需要加模板参数列表。

template <class T>
A<T>::~A()
{
  delete[] ptr;
  ptr = nullptr;
  _a = 0;
}

结尾语:以上是模板的基础应用,对于高级用法后面会更新的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

动名词

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

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

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

打赏作者

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

抵扣说明:

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

余额充值