C++模板初阶

Posted 山舟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++模板初阶相关的知识,希望对你有一定的参考价值。


一、泛型编程

以交换两个变量的值为例:

代码如下:

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;
}
void Swap(char& a, char& b) 
{
	char temp = a;
	a = b;
	b = temp;
}

//同理可写出unsigned int,float……类型的交换函数

函数重载可以存在多个同名的Swap函数、引用的使用已经比C语言已经方便了很多,但是以下两个方面仍很难处理:

(1)重载的函数仅仅只是类型不同,而逻辑完全相同,代码的复用率比较低,只要有新类型出现,就需要增加对应的函数。
(2)代码的可维护性比较低,由于逻辑相同,一个出错所有的重载均出错。

那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

C++提供模板template来实现。


二、函数模板

1.函数模板概念

函数模板代表了一个函数集合,该函数模板与类型无关,在使用时被参数化,根据实参类型产生适用于不同类型的函数。


2.函数模板格式

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

具体写法如下:

//T也可为其它名称
template<typename T>//注意没有逗号
void Swap(T& left, T& right) 
{
	T temp = left;
 	left = right;
 	right = temp; 
}

int main()
{
	//下面的Swap函数时两个不同的函数,因为他们的参数列表不同
	//一个参数是两个int,另一个的参数是两个double
	int a = 1, b = 2;
	Swap(a, b);
	double c = 3.14, d = 3.15;
	Swap(c, d);
	
	return 0;
}

调试查看反汇编代码,发现函数地址不同,显然是两个不同的函数。

查看反汇编结果如下:

typename是用来定义模板参数关键字的,也可以使用class,但切记不能使用struct代替class。

注意一个模板只能在之后的第一个函数中使用,剩余的函数无法再使用。

template<class X>
void Swap(X& a, X& b)
{
	X tmp = a;
	a = b;
	b = tmp;
}

void f(X a)//error
{}

3.函数模板的实例化

代码如下:

template<class T>
T add(T a, T b)
{
	return a + b;
}

int main()
{
	int a = 1, b = 2;
	add(a, b);//√
	double c = 3.14, d = 3.15;
	add(c, d);//√
	
	add(a, c);//error
	//该语句无法通过编译,编译器通过a推演得出T应为int,但通过c推演得出T应为double
	//二者矛盾,编译器无法确定T到底应该是哪一种类型,报错

	//以下两种办法可以解决
	//1.强制类型转换
	add(a, (int)c);
	
	//2.显式实例化:在函数名后的<>中指定模板参数的类型
	add<int>(a, c);
	add<double>(a, c);
	return 0;
}

三、类模板

1.类模板的定义

以顺序表为例,在C语言中,通过下面的方式使代码面对不同类型的数据时尽可能复用。

代码如下:

typedef int DataType;
struct Vector
{
	DataType _a;
	int _size;
	int _capacity;
};

//对顺序表的操作函数
//...

但是这也有一个问题,就是在同一份代码中,无法同时创建一个数据类型为int的顺序表和一个数据类型为double的顺序表,如果想要实现,又需要重写一份几乎完全相同的代码。


C++中可使用类模板来解决上述问题。

代码如下:

template<class T>

class Vector
{
public:
	//成员函数
	//...
private:
	T* _a;
	int _size;
	int _capacity;
};

int main()
{
	Vector<int> v1;//数据类型为int的顺序表v1
	Vector<double> v2;//数据类型为double的顺序表v2

	return 0;
}

2.类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,实例化的结果才是真正的类。
上面的代码中Vector是类名,Vector < int >才是类型。

模板不支持分离编译,也就是说声明放在.h文件中,而定义放在.cpp中。


感谢阅读,如有错误请批评指正

以上是关于C++模板初阶的主要内容,如果未能解决你的问题,请参考以下文章

C++模板初阶

C++初阶---模板入门

<c++> 四模板初阶

C++模板初阶

C++模板初阶--懒人创造世界

C++模板初阶--懒人创造世界