初识模板(泛型编程, 函数模板, 函数模板的实例化, 类模板, 类模板的实例化)

初识模板

1、泛型编程

编写与类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础

2、函数模板

2.1、函数模板的概念

函数模板代表一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本

2.2、函数模板的格式

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

}

typename是用来定义类模板参数的关键字,可以用class代替

2.3、函数模板的原理

模板本身不是函数,是编译器根据使用方式产生特定类型的模具
在程序编译阶段,编译器根据需要传入的实参类型来推演生成对应类型的函数以供调用。

#include <iostream>

using namespace std;

//函数模板
//函数模板代表一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本

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

template <typename T>
void Swap(T& left, T& right)
{
	T tmp = left;
	left = right;
	right = tmp;
}
//typename是用来定义类模板参数的关键字,可以用class代替

int main()
{
	char a = '0';
	char b = '9';
	Swap(a, b);
	cout << a << endl;
	cout << b << endl;

	int c = 10;
	int d = 20;
	Swap(c, d);
	cout << c << endl;
	cout << d << endl;

	double e = 2.1;
	double f = 3.2;
	Swap(e, f);
	cout << e << endl;
	cout << f << endl;

	system("pause");
	return 0;
}

2.4、函数模板的实例化

函数模板的实例化分为显示实例化和隐式实例化
如果类型不正确,编译器尝试隐式类型转换,若是失败,则报错

#include <iostream>

using namespace std;

//隐式实例化:让编译器根据实参类型自己推演模板参数的实际类型
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}

void Test1()
{
	int a = 10;
	int b = 20;
	double c = 10.5;
	double d = 20.8;

	cout << Add(a, b) << endl;
	cout << Add(c, d) << endl;

	//用户强制转化
	cout << Add(a, (int)c) << endl;
}

//显示实例化:在函数名后的<>中指定模板参数实际类型
void Test2()
{
	int a = 10;
	int b = 20;
	double c = 10.5;
	double d = 20.8;

	cout << Add<int>(a, b) << endl;
	cout << Add<double>(c, d) << endl;

	//用户强制转化
	cout << Add<int>(a, c) << endl;
}
int main()
{
	Test1();
	Test2();
	system("pause");
	return 0;
}

2.5、模板参数的匹配原则

1、一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以特化为这个非模板函数
2、对于非模板函数和同名函数模板,如果其他条件相同,在调动时优先调用非模板函数,若是模板可以产生一个更具有匹配效果的函数,则选择特化模板
3、模板函数不允许自动类型转换,但是普通函数可以

#include <iostream>

using namespace std;

//一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以特化为这个非模板函数
//
//专门处理int的加法函数
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;
//}
//
//void Test1()
//{
//	Add(1, 2);//与非模板函数匹配,编译器不需要特化
//	Add<int>(1, 2);//调用编译器特化的版本
//}

//对于非模板函数和同名函数模板,如果其他条件相同,在调动时优先调用非模板函数,若是模板可以产生一个更具有匹配效果的函数,则选择特化模板

//通用的加法函数
template<class T1, class T2>
T1 Add(const T1& left, const T2& right)
{
	return left + right;
}

void Test2()
{
	Add(1, 2);//不需要特化
	Add(1, 1.2);//模板函数可以生成更好的匹配版本,编译器根据实参生成更加匹配的Add函数
}

//模板函数不允许自动类型转换,但是普通函数可以

int main()
{
	//Test1();
	Test2();
	system("pause");
	return 0;
}

3、类模板

3.1、类模板概念

类模板代表一个类家族,该类模板与类型无关,在使用时被参数化,根据实参类型产生类的特定类型版本

3.2、类模板格式

template<class T1, class T2, …, class Tn>
class 类模板名
{
	//类体
}

3.3、类模板的实例化

类模板实例化需要在类模板名字后面加<>,然后将实例化的类型放在<>中即可。
注:实例化的结果才是真正的类

#include <iostream>

using namespace std;

//类模板代表一个类家族,该类模板与类型无关,在使用时被参数化,根据实参类型产生类的特定类型版本

//类模板的格式:
//template<class T1, class T2, …, class Tn>
//class 类模板名
//{
//	类体
//}

template<class T>
class Vector
{
public:
	Vector(size_t capacity)
		:_pData(new T[capacity])
		, _size(0)
		, _capacity(capacity)
	{

	}

	~Vector();

	void PushBack()
	{
		_pData[_size] = x;
		_size++;
	}

	size_t Size()
	{
		return _size;
	}

	T& operator[](size_t pos)
	{
		if (pos < _size)
		{
			return _pData[pos];
		}
	}

private:
	T* _pData;
	size_t _size;
	size_t _capacity;
};

//注:在类模板外面进行定义时要加模板参数列表
template<class T>
Vector<T>::~Vector()
{
	if (_pData)
	{
		delete[] _pData;
	}
	_size = 0;
	_capacity = 0;
}

//类模板实例化需要在类模板名字后面加<>,然后将实例化的类型放在<>中即可。
//注:实例化的结果才是真正的类
int main()
{
	Vector<int> s1(10);
	Vector<double> s2(20);
	system("pause");
	return 0;
}

发布了117 篇原创文章 · 获赞 48 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/gp1330782530/article/details/105248817