简单介绍C++中的模板

目录

一、泛型编程

泛型编程的概念:

泛型编程举例:

二、函数模板

函数模板的概念:

函数模板的格式:

函数模板的实例化:

隐式实例化:

显式实例化:

模板参数的匹配原则:

三、类模板

类模板的格式定义:

类模板的举例:

类模板的实例化:


当我们在编写程序时可能会遇见这样的问题:交换函数是使用频率非常高的函数,当我们想在一个工作台下同时交换char、int、double类型的数据时,我们要怎么做呢?

在C语言中,我们只能通过不同的函数名,对数据类型不同、函数功能相同的函数进行区分。

void Swapi(int left, int right) {//此处省略函数体}
void Swapd(double left, double right) {//此处省略函数体}
void Swapc(char left, char right){//此处省略函数体}
……

由于C++引入了函数重载的概念,使用相同的函数名,编译器可以根据形参的数据类型不同进行区分。

void Swap(int& left, int& right) {//此处省略函数体}
void Swap(double& left, double& right) {//此处省略函数体}
void Swap(char& left, char& right){//此处省略函数体}
……

使用函数重载虽然可以实现,但有几个不好的地方:

  1. 函数从在仅仅时类型不同,代码复用率低,有新类型出现时需要用户自己增加对应函数
  2. 代码可维护性低,当代码出错时,可能需要对所有的代码都需要修改

仔细观察会发现,上述代码只有数据类型不同,其他代码实现都相同。那么是否可以将代码作为模具,将数据类型设为X(未知数据类型),在具体调用时,再将实际的数据类型和X进行替换,就可以实现一份代码,解决函数重载带来的所有问题。因此,引入了泛型编程的思想。

一、泛型编程

泛型编程的概念:

泛型编程是一种编程范式,它的目的是提高代码的重用性和灵活性。泛型编程允许程序员使用不同的数据类型来实现相同的算法和数据结构,从而编写更加通用和可扩展的代码。

泛型编程举例:

实现一个通用的交换函数

//template模板关键字,typename模板中数据类型不是固定的,需要编译器自动推导
template<typename T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

int main()
{
	int a = 10, b = 20;
	double c = 10.12, d = 20.34;
	Swap(a, b);
	Swap(c, d);
	cout << "a:" << a << "    " << "b:" << b << endl;
	cout << "c:" << c << "    " << "d:" << d << endl;

	return 0;
}

二、函数模板

函数模板的概念:

函数模板是一种通用的函数定义形式,允许定义一个接受任意类型参数的函数。它的定义形式类似于一个普通函数,但是使用了类型占位符(通常为T)来代替具体类型。在函数调用时,编译器会根据调用时传递的参数类型来确定T的具体值并生成相应的函数实例。

函数模板的格式:

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表) {}
template<typename T>//typename是用来定义模板参数关键字,也可以使用class
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

函数模板的实例化:

函数模板并不是实际存在的,只有当系统调用时,才会根据传递过去的实际类型进行实例化。分为隐式实例化和显式实例化

隐式实例化:

编译器根据实参,推演模板参数的实际类型

template<class T>
T Add(const T& left, const T& right) { return left + right; }
int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, a2);//实参是int,编译器将T替换成int,实例化出具体函数
	Add(d1, d2);
    
    //Add(a1, d1);//注意:在模板中,编译器一般不会进行类型转换操作,实参是int和double两种类型,编译器会报错

    //想解决这种问题有两种方式:1、类型转换;2、显式实例化
    Add(a1, (int)d1);

	return 0;
}

显式实例化:

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

template<class T>
T Add(const T& left, const T& right) { return left + right; }
int main()
{
	int a = 10;
	double b = 20.4;

	// 显式实例化
	Add<int>(a, b);//如果实参类型和指定的类型不匹配,会进行类型转换,失败会报错

	return 0;
}

模板参数的匹配原则:

一个非模板参数和一个同名的函数模板同时存在,如果其他条件都相同,首选非模板参数

//非模板函数
int Add(const int& left, const int& right) { return left + right; }

//模板函数
template<class T>
T Add(const T& left, const T& right) { return left + right; }

int main()
{

	Add(1, 2);//首选非模板函数
	Add<int>(1, 2);//显示实例化,会选择模板函数

	return 0;
}

一个非模板函数和一个同名的函数模板同时存在,函数模板生成的函数更加匹配,会选择函数模板

//非模板函数
int Add(const int& left, const int& right) { return left + right; }

//模板函数
template<class T1,class T2>
T1 Add(const T1& left, const T2& right) { return left + right; }

int main()
{

	Add(1, 2);//与非模板函数参数类型相同,首选非模板函数
	Add(1, 2.0);//与模板函数生成的函数更匹配,选择模板函数

	return 0;
}

函数模板不能进行隐式类型转换,非模板函数可以进行隐式类型转换

三、类模板

类模板的格式定义:

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

类模板的举例:

//模拟vector
//vextor不是一个具体的类,编译器会根据实例化的具体类型从而生成具体类的容器
template<class T>
class vector
{
public:
	vector(size_t capacity = 10)
		:_pData(new T[capacity])
		,_size(0)
		,_capacity(capacity)
	{ }
	
	//……以下细节省略
private:
	T* _pData;
	size_t _size;
	size_t _capacity;
};

类模板的实例化:

template<class T>
class vector
{
public:
	vector(size_t capacity = 10)
		:_pData(new T[capacity])
		,_size(0)
		,_capacity(capacity)
	{ }
	
	//……以下细节省略
private:
	T* _pData;
	size_t _size;
	size_t _capacity;
};

int main()
{
	//使用显式实例化指定类型
	vector<int> v1;

	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ljiyu0506

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

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

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

打赏作者

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

抵扣说明:

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

余额充值