C++ 泛型编程的基础--模板初识及应用

了解模板之前我们要先知道什么是泛型编程:泛型编程的代表作品STL是一种高效、泛型、可交互操作的软件组件。STL以迭代器 (Iterators)和容器(Containers)为基础,是一种泛型算法(Generic Algorithms)库。泛型编程让你编写完全一般化并可重复使用的算法,其效率与针对某特定数据类型而设计的算法相同。泛型即是指具有在多种数据类型上皆可操作的含义,而模板也是泛型编程中的一种典型例子。

函数模板

模板我们生活中也听得不少了,建房时都会有图纸,然后人们可以通过图纸来建房的基本框架。有了基本框架,任何人都可以进行自己喜欢的类型风格来装修。在C++中,模板就像图纸,我们写好了模板,也就有了基本的框架,装修风格就像C++中的类型千变万化,编译器最终会通过类型来推演出我们最终想要的函数或类。

交换函数是我们编程或刷题中最常见的函数之一,即使我们有了重载函数,但是还是因为变量的类型不同而要写多个交换函数。现在,你学会了模板,无论多少种类型变量的交换,都只要写一次就能完成。

声明模板格式:template<typename T1,typename T2,typename T3, ...>,在函数或者类的上面添加,及表示该函数为模板函数或者模板类。注:typename可以替换成class,但是不能使用struct。

//声明模板
template <typename T>
void Swap(T& left, T& right)
{
	T tmp = left;
	left = right;
	right = tmp;
}

如何使用呢?

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

void test()
{
	int a = 1;
	int b = 2;
	Swap(a, b);
	cout << a << " " << b << endl;
	double c = 1.1;
	double d = 2.2;
	Swap(c, d);
	cout << c << " " << d << endl;
	char e = 'a';
	char f = 'b';
	Swap(e, f);
	cout << e << " " << f << endl;
}

在这里插入图片描述
看上去每次Swap都会调用模板函数,但是底层其实不是这样子的,编译阶段,编译器会将你传入的实参来推演出模板函数的类型,产生一个新的函数,并将T替换成相对应的类型,再调用这个新的函数。我们可以通过反汇编来看看新的函数的地址。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
函数的地址都是不一样的,且函数名后都会加上传入的实参的类型,我们再来看一张图,加深我们对模板底层的理解。
在这里插入图片描述
看到这里你一定理解和使用模板了吧,可能会有很多小伙伴想钻牛角尖,说能不能传两个不一样的类型,让编译器去推导呢?你看你坏的很,编译器不知道你想转换成哪种类型,他是不会帮你转换的。如果明确要转换的类型,编译器才会转换。
在这里插入图片描述

那我们想让编译器推导参数不同类型的函数可以吗?当然可以,那就必须显示实例化或者将参数强转成对应的类型

template<typename T>
T Add(T left, T right)
{
	return left + right;
}

void test()
{
	int a = 1;
	double b = 1.1;

	//1、显示实例化 (告诉编译器生成类型为int的Add函数)
	Add<int>(a, b);
	//2、强转为int,此时参数类型一致
	Add(a, (int)b);
}

1、当一个非模板函数和一个同名模板函数同时存在时,会优先调用非模板函数
在这里插入图片描述
2、非模板函数和同名模板函数同时存在,编译器会根据传入的参数匹配更好的函数
在这里插入图片描述
3、如果知名需要进行实例化,则直接实例化,不管是否存在同名非模板函数
在这里插入图片描述

类模板

定义类模板和函数模板方式一样,在类前声明模板

template <class T>
class seqList
{
public:
	seqList(int n)
		:_data(new T[n])
		, _size(0)
		, _capacity(n)
	{}
private:
	T* _data;
	size_t _size;
	size_t _capacity;
};

如果在类中声明成员函数,要在类外定义函数,那么定义函数时也要在前面加上模板声明

template <class T>
class seqList
{
public:
	seqList(int n)
		:_data(new T[n])
		, _size(0)
		, _capacity(n)
	{}
	
	//声明成员模板函数
	T seqListAt(size_t pos);
private:
	T* _data;
	size_t _size;
	size_t _capacity;
};

//类外定义成员函数
template <class T>
T seqList<T>::seqListAt(size_t pos)
{
	return _data[pos];
}

在我们实例化对象时,因为是自定义类型,编译器无法推导出我们想要的类的类型,所以我们必须显示实例化。
格式类名<类型> 对象名(参数)

	//类模板实例化:类名<类型> 对象名(参数)
	seqList<int> sq1(2);
	seqList<double> sq2(4);
	seqList<char> sq3(6);

推荐阅读

C++ 泛型模板进阶

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

WhiteShirtI

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

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

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

打赏作者

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

抵扣说明:

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

余额充值